Netty中NioEventLoopGroup的創建源碼分析

NioEventLoopGroup的無參構造:

public NioEventLoopGroup() {
	this(0);
}

調用了單參的構造:

public NioEventLoopGroup(int nThreads) {
    this(nThreads, (Executor)null);
}

繼續看到雙參構造:

public NioEventLoopGroup(int nThreads, Executor executor) {
    this(nThreads, executor, SelectorProvider.provider());
}

在這裏是使用JDK中NIO的原生API:SelectorProvider的provider,產生了一個SelectorProvider對象調用,繼續調用三參構造。
關於SelectorProvider在我前面的博客中有介紹過:【Java】NIO中Selector的創建源碼分析,在Windows下默認創建了WindowsSelectorProvider對象。

繼續看三參構造:

public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, SelectorProvider selectorProvider) {
    this(nThreads, threadFactory, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}

在這裏創建了一個單例的DefaultSelectStrategyFactory 對象:

public final class DefaultSelectStrategyFactory implements SelectStrategyFactory {
    public static final SelectStrategyFactory INSTANCE = new DefaultSelectStrategyFactory();

    private DefaultSelectStrategyFactory() {
    }

    public SelectStrategy newSelectStrategy() {
        return DefaultSelectStrategy.INSTANCE;
    }
}

DefaultSelectStrategyFactory實現的是SelectStrategyFactory 接口:

public interface SelectStrategyFactory {
    SelectStrategy newSelectStrategy();
}

該接口提供一個用來產生Select策略的方法,SelectStrategy接口如下:

public interface SelectStrategy {
    int SELECT = -1;
    int CONTINUE = -2;

    int calculateStrategy(IntSupplier var1, boolean var2) throws Exception;
}

根據IntSupplier 和一個boolean值爲Select策略提供了一個計算策略的方法。
在Netty中只提供了DefaultSelectStrategy這一種默認實現:

final class DefaultSelectStrategy implements SelectStrategy {
    static final SelectStrategy INSTANCE = new DefaultSelectStrategy();

    private DefaultSelectStrategy() {
    }

    public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
        return hasTasks ? selectSupplier.get() : -1;
    }
}

其中IntSupplier :

public interface IntSupplier {
    int get() throws Exception;
}

結合上面的來看,最終的選擇策略主要是根據IntSupplier的get值來得到的。

再回到構造:

public NioEventLoopGroup(int nThreads, ThreadFactory threadFactory, SelectorProvider selectorProvider, SelectStrategyFactory selectStrategyFactory) {
    super(nThreads, threadFactory, new Object[]{selectorProvider, selectStrategyFactory, RejectedExecutionHandlers.reject()});
}

這裏產生了一個拒絕策略:

public static RejectedExecutionHandler reject() {
	return REJECT;
}

private static final RejectedExecutionHandler REJECT = new RejectedExecutionHandler() {
	public void rejected(Runnable task, SingleThreadEventExecutor executor) {
		throw new RejectedExecutionException();
	}
};

public interface RejectedExecutionHandler {
	void rejected(Runnable var1, SingleThreadEventExecutor var2);
}

將selectorProvider、selectStrategyFactory以及這個拒絕策略封裝在一個Object數組裏,再調用了父類MultithreadEventLoopGroup的構造:

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

在這裏對nThreads的大小進行了調整:

private static final int DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt("io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));

SystemPropertyUtil.getInt是根據key值"io.netty.eventLoopThreads",獲取系統配置值,在沒用設置時使用NettyRuntime.availableProcessors() * 2的值
NettyRuntime的availableProcessors實現如下:

synchronized int availableProcessors() {
    if (this.availableProcessors == 0) {
        int availableProcessors = SystemPropertyUtil.getInt("io.netty.availableProcessors", Runtime.getRuntime().availableProcessors());
        this.setAvailableProcessors(availableProcessors);
    }

    return this.availableProcessors;
}

還是一樣,根據key值"io.netty.availableProcessors",獲取系統配置值,在沒用設置時使用Runtime.getRuntime().availableProcessors(),是用來獲取處理器的個數。

這樣保證了在默認情況下nThreads的大小是總是cpu個數的2倍。

繼續回到構造,MultithreadEventLoopGroup繼續調用父類MultithreadEventExecutorGroup的構造:

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
    this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}

在這裏又初始化了一個單例的DefaultEventExecutorChooserFactory對象:

public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();

DefaultEventExecutorChooserFactory 實現的是EventExecutorChooserFactory接口:

public interface EventExecutorChooserFactory {
    EventExecutorChooserFactory.EventExecutorChooser newChooser(EventExecutor[] var1);

    public interface EventExecutorChooser {
        EventExecutor next();
    }
}

DefaultEventExecutorChooserFactory 的具體實現:

public EventExecutorChooser newChooser(EventExecutor[] executors) {
    return (EventExecutorChooser)(isPowerOfTwo(executors.length) ? new DefaultEventExecutorChooserFactory.PowerOfTwoEventExecutorChooser(executors) : new DefaultEventExecutorChooserFactory.GenericEventExecutorChooser(executors));
}

private static boolean isPowerOfTwo(int val) {
    return (val & -val) == val;
}

isPowerOfTwo是用來檢查executors的大小是否是二的整數次方,若是二的整數次方,產生PowerOfTwoEventExecutorChooser,反之產生GenericEventExecutorChooser:

private static final class GenericEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;

    GenericEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }

    public EventExecutor next() {
        return this.executors[Math.abs(this.idx.getAndIncrement() % this.executors.length)];
    }
}

private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
    private final AtomicInteger idx = new AtomicInteger();
    private final EventExecutor[] executors;

    PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
        this.executors = executors;
    }

    public EventExecutor next() {
        return this.executors[this.idx.getAndIncrement() & this.executors.length - 1];
    }
}

這兩種其實都是用了取模運算,只不過因爲二的整數次方的特殊性而使用位運算。

回到構造,MultithreadEventExecutorGroup繼續調用本省的構造:

private final EventExecutor[] children;
private final Set<EventExecutor> readonlyChildren;
private final AtomicInteger terminatedChildren;
private final Promise<?> terminationFuture;
private final EventExecutorChooser chooser;

protected MultithreadEventExecutorGroup(int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... args) {
    this.terminatedChildren = new AtomicInteger();
    this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    if (nThreads <= 0) {
        throw new IllegalArgumentException(String.format("nThreads: %d (expected: > 0)", nThreads));
    } else {
        if (executor == null) {
            executor = new ThreadPerTaskExecutor(this.newDefaultThreadFactory());
        }

        this.children = new EventExecutor[nThreads];

        int j;
        for(int i = 0; i < nThreads; ++i) {
            boolean success = false;
            boolean var18 = false;

            try {
                var18 = true;
                this.children[i] = this.newChild((Executor)executor, args);
                success = true;
                var18 = false;
            } catch (Exception var19) {
                throw new IllegalStateException("failed to create a child event loop", var19);
            } finally {
                if (var18) {
                    if (!success) {
                        int j;
                        for(j = 0; j < i; ++j) {
                            this.children[j].shutdownGracefully();
                        }

                        for(j = 0; j < i; ++j) {
                            EventExecutor e = this.children[j];

                            try {
                                while(!e.isTerminated()) {
                                    e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                                }
                            } catch (InterruptedException var20) {
                                Thread.currentThread().interrupt();
                                break;
                            }
                        }
                    }

                }
            }

            if (!success) {
                for(j = 0; j < i; ++j) {
                    this.children[j].shutdownGracefully();
                }

                for(j = 0; j < i; ++j) {
                    EventExecutor e = this.children[j];

                    try {
                        while(!e.isTerminated()) {
                            e.awaitTermination(2147483647L, TimeUnit.SECONDS);
                        }
                    } catch (InterruptedException var22) {
                        Thread.currentThread().interrupt();
                        break;
                    }
                }
            }
        }

        this.chooser = chooserFactory.newChooser(this.children);
        FutureListener<Object> terminationListener = new FutureListener<Object>() {
            public void operationComplete(Future<Object> future) throws Exception {
                if (MultithreadEventExecutorGroup.this.terminatedChildren.incrementAndGet() == MultithreadEventExecutorGroup.this.children.length) {
                    MultithreadEventExecutorGroup.this.terminationFuture.setSuccess((Object)null);
                }

            }
        };
        EventExecutor[] var24 = this.children;
        j = var24.length;

        for(int var26 = 0; var26 < j; ++var26) {
            EventExecutor e = var24[var26];
            e.terminationFuture().addListener(terminationListener);
        }

        Set<EventExecutor> childrenSet = new LinkedHashSet(this.children.length);
        Collections.addAll(childrenSet, this.children);
        this.readonlyChildren = Collections.unmodifiableSet(childrenSet);
    }
}

首先是對terminatedChildren的初始化,沒什麼好說的,對terminationFuture的初始化使用DefaultPromise,用來異步處理終止事件。executor初始化產生一個線程池。

接下來就是對children的操作,根據nThreads的大小,產生一個EventExecutor數組,然後遍歷這個數組,調用newChild給每一個元素初始化。

newChild是在NioEventLoopGroup中實現的:

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

在這裏直接使用executor,和之前放在args數組中的SelectorProvider、SelectStrategyFactory(newSelectStrategy方法產生DefaultSelectStrategy)和RejectedExecutionHandler產生了一個NioEventLoop對象:

private Selector selector;
private Selector unwrappedSelector;
private SelectedSelectionKeySet selectedKeys;
private final SelectorProvider provider;
private final AtomicBoolean wakenUp = new AtomicBoolean();
private final SelectStrategy selectStrategy;

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");
    } else if (strategy == null) {
        throw new NullPointerException("selectStrategy");
    } else {
        this.provider = selectorProvider;
        NioEventLoop.SelectorTuple selectorTuple = this.openSelector();
        this.selector = selectorTuple.selector;
        this.unwrappedSelector = selectorTuple.unwrappedSelector;
        this.selectStrategy = strategy;
    }
}

NioEventLoop首先在繼承鏈上調用父類的構造,都是一些成員的賦值操作,簡單看一看:

protected SingleThreadEventLoop(EventLoopGroup parent, Executor executor, boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedExecutionHandler) {
    super(parent, executor, addTaskWakesUp, maxPendingTasks, rejectedExecutionHandler);
    this.tailTasks = this.newTaskQueue(maxPendingTasks);
}

protected SingleThreadEventExecutor(EventExecutorGroup parent, Executor executor, boolean addTaskWakesUp, int maxPendingTasks, RejectedExecutionHandler rejectedHandler) {
    super(parent);
    this.threadLock = new Semaphore(0);
    this.shutdownHooks = new LinkedHashSet();
    this.state = 1;
    this.terminationFuture = new DefaultPromise(GlobalEventExecutor.INSTANCE);
    this.addTaskWakesUp = addTaskWakesUp;
    this.maxPendingTasks = Math.max(16, maxPendingTasks);
    this.executor = (Executor)ObjectUtil.checkNotNull(executor, "executor");
    this.taskQueue = this.newTaskQueue(this.maxPendingTasks);
    this.rejectedExecutionHandler = (RejectedExecutionHandler)ObjectUtil.checkNotNull(rejectedHandler, "rejectedHandler");
}

protected AbstractScheduledEventExecutor(EventExecutorGroup parent) {
    super(parent);
}

protected AbstractEventExecutor(EventExecutorGroup parent) {
    this.selfCollection = Collections.singleton(this);
    this.parent = parent;
}

在經過這繼承鏈上的一系列調用後,給provider成員賦值selectorProvider,就是之前創建好的WindowsSelectorProvider,然後使用openSelector方法,最終創建JDK原生的Selector:

private NioEventLoop.SelectorTuple openSelector() {
    final AbstractSelector unwrappedSelector;
    try {
        unwrappedSelector = this.provider.openSelector();
    } catch (IOException var7) {
        throw new ChannelException("failed to open a new selector", var7);
    }

    if (DISABLE_KEYSET_OPTIMIZATION) {
        return new NioEventLoop.SelectorTuple(unwrappedSelector);
    } else {
        final SelectedSelectionKeySet selectedKeySet = new SelectedSelectionKeySet();
        Object maybeSelectorImplClass = AccessController.doPrivileged(new PrivilegedAction<Object>() {
            public Object run() {
                try {
                    return Class.forName("sun.nio.ch.SelectorImpl", false, PlatformDependent.getSystemClassLoader());
                } catch (Throwable var2) {
                    return var2;
                }
            }
        });
        if (maybeSelectorImplClass instanceof Class && ((Class)maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) {
            final Class<?> selectorImplClass = (Class)maybeSelectorImplClass;
            Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
                public Object run() {
                    try {
                        Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys");
                        Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys");
                        Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true);
                        if (cause != null) {
                            return cause;
                        } else {
                            cause = ReflectionUtil.trySetAccessible(publicSelectedKeysField, true);
                            if (cause != null) {
                                return cause;
                            } else {
                                selectedKeysField.set(unwrappedSelector, selectedKeySet);
                                publicSelectedKeysField.set(unwrappedSelector, selectedKeySet);
                                return null;
                            }
                        }
                    } catch (NoSuchFieldException var4) {
                        return var4;
                    } catch (IllegalAccessException var5) {
                        return var5;
                    }
                }
            });
            if (maybeException instanceof Exception) {
                this.selectedKeys = null;
                Exception e = (Exception)maybeException;
                logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, e);
                return new NioEventLoop.SelectorTuple(unwrappedSelector);
            } else {
                this.selectedKeys = selectedKeySet;
                logger.trace("instrumented a special java.util.Set into: {}", unwrappedSelector);
                return new NioEventLoop.SelectorTuple(unwrappedSelector, new SelectedSelectionKeySetSelector(unwrappedSelector, selectedKeySet));
            }
        } else {
            if (maybeSelectorImplClass instanceof Throwable) {
                Throwable t = (Throwable)maybeSelectorImplClass;
                logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t);
            }

            return new NioEventLoop.SelectorTuple(unwrappedSelector);
        }
    }
}

可以看到在一開始就使用provider的openSelector方法,即WindowsSelectorProvider的openSelector方法,創建了WindowsSelectorImpl對象(【Java】NIO中Selector的創建源碼分析

然後根據DISABLE_KEYSET_OPTIMIZATION判斷:

private static final boolean DISABLE_KEYSET_OPTIMIZATION = SystemPropertyUtil.getBoolean("io.netty.noKeySetOptimization", false);

可以看到這個系統配置在沒有設置默認是false,如果設置了則直接創建一個SelectorTuple對象返回:

private static final class SelectorTuple {
    final Selector unwrappedSelector;
    final Selector selector;

    SelectorTuple(Selector unwrappedSelector) {
        this.unwrappedSelector = unwrappedSelector;
        this.selector = unwrappedSelector;
    }

    SelectorTuple(Selector unwrappedSelector, Selector selector) {
        this.unwrappedSelector = unwrappedSelector;
        this.selector = selector;
    }
}

可以看到僅僅是將unwrappedSelector和selector封裝了,unwrappedSelector對應的是JDK原生Selector沒有經過更改的,而selector對應的是經過更改修飾操作的。

在沒有系統配置下,就對Selector進行更改修飾操作:
首先創建SelectedSelectionKeySet對象,這個SelectedSelectionKeySet繼承自AbstractSet:

final class SelectedSelectionKeySet extends AbstractSet<SelectionKey> {
	SelectionKey[] keys = new SelectionKey[1024];
	int size;
	
	SelectedSelectionKeySet() {
	}
	......
}

後面是通過反射機制,使得WindowsSelectorImpl的selectedKeys和publicSelectedKeys成員直接賦值爲SelectedSelectionKeySet對象。

WindowsSelectorImpl的這兩個成員是在SelectorImpl中定義的:

protected Set<SelectionKey> selectedKeys = new HashSet();
private Set<SelectionKey> publicSelectedKeys;

從這裏就可以明白,在JDK原生的Selector中,selectedKeys和publicSelectedKeys這兩個Set的初始化大小都爲0,而在這裏僅僅就是使其初始化大小變爲1024。
後面就是對一些異常的處理,沒什麼好說的。

openSelector結束後,就可以分別對包裝過的Selector和未包裝過的Selector,即selector和unwrappedSelector成員賦值,再由selectStrategy保存剛纔產生的選擇策略,用於Selector的輪詢。

回到MultithreadEventExecutorGroup的構造,在調用newChild方法時即NioEventLoop創建的過程中可能出現異常情況,就需要遍歷children數組,將之前創建好的NioEventLoop使用shutdownGracefully優雅地關閉掉:
shutdownGracefully在AbstractEventExecutor中實現:

public Future<?> shutdownGracefully() {
	return this.shutdownGracefully(2L, 15L, TimeUnit.SECONDS);
}

這裏設置了超時時間,繼續調用SingleThreadEventExecutor的shutdownGracefully方法:

public Future<?> shutdownGracefully(long quietPeriod, long timeout, TimeUnit unit) {
    if (quietPeriod < 0L) {
        throw new IllegalArgumentException("quietPeriod: " + quietPeriod + " (expected >= 0)");
    } else if (timeout < quietPeriod) {
        throw new IllegalArgumentException("timeout: " + timeout + " (expected >= quietPeriod (" + quietPeriod + "))");
    } else if (unit == null) {
        throw new NullPointerException("unit");
    } else if (this.isShuttingDown()) {
        return this.terminationFuture();
    } else {
        boolean inEventLoop = this.inEventLoop();

        while(!this.isShuttingDown()) {
            boolean wakeup = true;
            int oldState = this.state;
            int newState;
            if (inEventLoop) {
                newState = 3;
            } else {
                switch(oldState) {
                case 1:
                case 2:
                    newState = 3;
                    break;
                default:
                    newState = oldState;
                    wakeup = false;
                }
            }

            if (STATE_UPDATER.compareAndSet(this, oldState, newState)) {
                this.gracefulShutdownQuietPeriod = unit.toNanos(quietPeriod);
                this.gracefulShutdownTimeout = unit.toNanos(timeout);
                if (oldState == 1) {
                    try {
                        this.doStartThread();
                    } catch (Throwable var10) {
                        STATE_UPDATER.set(this, 5);
                        this.terminationFuture.tryFailure(var10);
                        if (!(var10 instanceof Exception)) {
                            PlatformDependent.throwException(var10);
                        }

                        return this.terminationFuture;
                    }
                }

                if (wakeup) {
                    this.wakeup(inEventLoop);
                }

                return this.terminationFuture();
            }
        }

        return this.terminationFuture();
    }
}

前三個判斷沒什麼好說的,isShuttingDown判斷:

public boolean isShuttingDown() {
    return this.state >= 3;
}

在之前NioEventLoop創建的時候,調用了一系列的繼承鏈,其中state是在SingleThreadEventExecutor的構造方法中實現的,初始值是1,state有如下幾種狀態:

private static final int ST_NOT_STARTED = 1;
private static final int ST_STARTED = 2;
private static final int ST_SHUTTING_DOWN = 3;
private static final int ST_SHUTDOWN = 4;
private static final int ST_TERMINATED = 5;

可見在NioEventLoop初始化後處於尚未啓動狀態,並沒有Channel的註冊,也就不需要輪詢。

isShuttingDown就必然是false,就進入了else塊:
首先得到inEventLoop的返回值,該方法在AbstractEventExecutor中實現:

public boolean inEventLoop() {
    return this.inEventLoop(Thread.currentThread());
}

他傳入了一個當前線程,接着調用inEventLoop的重載,這個方法是在SingleThreadEventExecutor中實現:

public boolean inEventLoop(Thread thread) {
    return thread == this.thread;
}

通過觀察之前的SingleThreadEventExecutor構造方法,發現並沒有對thread成員初始化,此時的this.thread就是null,那麼返回值就是false,即inEventLoop爲false。

在while循環中又對isShuttingDown進行了判斷,shutdownGracefully當讓不僅僅使用在創建NioEventLoop對象失敗時才調用的,無論是在EventLoopGroup的關閉,還是Bootstrap的關閉,都會關閉綁定的NioEventLoop,所以在多線程環境中,有可能會被其他線程關閉。

在while循環中,結合上面可知滿足進入switch塊,在switch塊中令newState爲3;
然後調用STATE_UPDATER的compareAndSet方法,STATE_UPDATER是用來原子化更新state成員的:

private static final AtomicIntegerFieldUpdater<SingleThreadEventExecutor> STATE_UPDATER = AtomicIntegerFieldUpdater.newUpdater(SingleThreadEventExecutor.class, "state");

所以這裏就是使用CAS操作,原子化更新state成員爲3,也就是使當前狀態由ST_NOT_STARTED 變爲了ST_SHUTTING_DOWN 狀態。

gracefulShutdownQuietPeriod和gracefulShutdownTimeout分別保存quietPeriod和timeout的納秒級顆粒度。

前面可知oldState使1,調用doStartThread方法:

private void doStartThread() {
    assert this.thread == null;

    this.executor.execute(new Runnable() {
        public void run() {
            SingleThreadEventExecutor.this.thread = Thread.currentThread();
            if (SingleThreadEventExecutor.this.interrupted) {
                SingleThreadEventExecutor.this.thread.interrupt();
            }

            boolean success = false;
            SingleThreadEventExecutor.this.updateLastExecutionTime();
            boolean var112 = false;

            int oldState;
            label1685: {
                try {
                    var112 = true;
                    SingleThreadEventExecutor.this.run();
                    success = true;
                    var112 = false;
                    break label1685;
                } catch (Throwable var119) {
                    SingleThreadEventExecutor.logger.warn("Unexpected exception from an event executor: ", var119);
                    var112 = false;
                } finally {
                    if (var112) {
                        int oldStatex;
                        do {
                            oldStatex = SingleThreadEventExecutor.this.state;
                        } while(oldStatex < 3 && !SingleThreadEventExecutor.STATE_UPDATER.compareAndSet(SingleThreadEventExecutor.this, oldStatex, 3));

                        if (success && SingleThreadEventExecutor.this.gracefulShutdownStartTime == 0L) {
                            SingleThreadEventExecutor.logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " + SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must be called before run() implementation terminates.");
                        }

                        try {
                            while(!SingleThreadEventExecutor.this.confirmShutdown()) {
                                ;
                            }
                        } finally {
                            try {
                                SingleThreadEventExecutor.this.cleanup();
                            } finally {
                                SingleThreadEventExecutor.STATE_UPDATER.set(SingleThreadEventExecutor.this, 5);
                                SingleThreadEventExecutor.this.threadLock.release();
                                if (!SingleThreadEventExecutor.this.taskQueue.isEmpty()) {
                                    SingleThreadEventExecutor.logger.warn("An event executor terminated with non-empty task queue (" + SingleThreadEventExecutor.this.taskQueue.size() + ')');
                                }

                                SingleThreadEventExecutor.this.terminationFuture.setSuccess((Object)null);
                            }
                        }

                    }
                }

                do {
                    oldState = SingleThreadEventExecutor.this.state;
                } while(oldState < 3 && !SingleThreadEventExecutor.STATE_UPDATER.compareAndSet(SingleThreadEventExecutor.this, oldState, 3));

                if (success && SingleThreadEventExecutor.this.gracefulShutdownStartTime == 0L) {
                    SingleThreadEventExecutor.logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " + SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must be called before run() implementation terminates.");
                }

                try {
                    while(!SingleThreadEventExecutor.this.confirmShutdown()) {
                        ;
                    }

                    return;
                } finally {
                    try {
                        SingleThreadEventExecutor.this.cleanup();
                    } finally {
                        SingleThreadEventExecutor.STATE_UPDATER.set(SingleThreadEventExecutor.this, 5);
                        SingleThreadEventExecutor.this.threadLock.release();
                        if (!SingleThreadEventExecutor.this.taskQueue.isEmpty()) {
                            SingleThreadEventExecutor.logger.warn("An event executor terminated with non-empty task queue (" + SingleThreadEventExecutor.this.taskQueue.size() + ')');
                        }

                        SingleThreadEventExecutor.this.terminationFuture.setSuccess((Object)null);
                    }
                }
            }

            do {
                oldState = SingleThreadEventExecutor.this.state;
            } while(oldState < 3 && !SingleThreadEventExecutor.STATE_UPDATER.compareAndSet(SingleThreadEventExecutor.this, oldState, 3));

            if (success && SingleThreadEventExecutor.this.gracefulShutdownStartTime == 0L) {
                SingleThreadEventExecutor.logger.error("Buggy " + EventExecutor.class.getSimpleName() + " implementation; " + SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must be called before run() implementation terminates.");
            }

            try {
                while(!SingleThreadEventExecutor.this.confirmShutdown()) {
                    ;
                }
            } finally {
                try {
                    SingleThreadEventExecutor.this.cleanup();
                } finally {
                    SingleThreadEventExecutor.STATE_UPDATER.set(SingleThreadEventExecutor.this, 5);
                    SingleThreadEventExecutor.this.threadLock.release();
                    if (!SingleThreadEventExecutor.this.taskQueue.isEmpty()) {
                        SingleThreadEventExecutor.logger.warn("An event executor terminated with non-empty task queue (" + SingleThreadEventExecutor.this.taskQueue.size() + ')');
                    }

                    SingleThreadEventExecutor.this.terminationFuture.setSuccess((Object)null);
                }
            }

        }
    });
}

剛纔說過this.thread並沒有初始化,所以等於null成立,斷言可以繼續。

然後直接使executor運行了一個線程,這個executor其實就是在剛纔的MultithreadEventExecutorGroup中產生的ThreadPerTaskExecutor對象。

在線程中,首先將SingleThreadEventExecutor的thread成員初始化爲當前線程。

在這裏可能就有疑問了,爲什麼會在關閉時會調用名爲doStartThread的方法,這個方法不因該在啓動時調用嗎?
其實doStartThread在啓動時是會被調用的,當在啓動時被調用的話,每一個NioEventLoop都會被綁定一個線程用來處理真正的Selector操作,根據之前的說法就可以知道,每個EventLoopGroup在創建後都會被綁定cpu個數的二倍個NioEventLoop,而每個NioEventLoop都會綁定一個Selector對象,上面又說了在啓動時SingleThreadEventExecutor綁定了一個線程,即NioEventLoop綁定了一個線程來處理其綁定的Selector的輪詢。
至於關閉時還會啓動Selector的輪詢,就是爲了解決註冊了的Channel沒有被處理的情況。

回到doStartThread方法,其實這個doStartThread方法的核心是SingleThreadEventExecutor.this.run(),這個方法就是正真的Selector的輪詢操作,在NioEventLoop中實現:

protected void run() {
    while(true) {
        while(true) {
            try {
                switch(this.selectStrategy.calculateStrategy(this.selectNowSupplier, this.hasTasks())) {
                case -2:
                    continue;
                case -1:
                    this.select(this.wakenUp.getAndSet(false));
                    if (this.wakenUp.get()) {
                        this.selector.wakeup();
                    }
                default:
                    this.cancelledKeys = 0;
                    this.needsToSelectAgain = false;
                    int ioRatio = this.ioRatio;
                    if (ioRatio == 100) {
                        try {
                            this.processSelectedKeys();
                        } finally {
                            this.runAllTasks();
                        }
                    } else {
                        long ioStartTime = System.nanoTime();
                        boolean var13 = false;

                        try {
                            var13 = true;
                            this.processSelectedKeys();
                            var13 = false;
                        } finally {
                            if (var13) {
                                long ioTime = System.nanoTime() - ioStartTime;
                                this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
                            }
                        }

                        long ioTime = System.nanoTime() - ioStartTime;
                        this.runAllTasks(ioTime * (long)(100 - ioRatio) / (long)ioRatio);
                    }
                }
            } catch (Throwable var21) {
                handleLoopException(var21);
            }

            try {
                if (this.isShuttingDown()) {
                    this.closeAll();
                    if (this.confirmShutdown()) {
                        return;
                    }
                }
            } catch (Throwable var18) {
                handleLoopException(var18);
            }
        }
    }
}

進入switch塊,首先調用之前準備好的選擇策略,其中this.selectNowSupplier在NioEventLoop創建的時候就被創建了:

private final IntSupplier selectNowSupplier = new IntSupplier() {
    public int get() throws Exception {
        return NioEventLoop.this.selectNow();
    }
};

實際上調用了selectNow方法:

int selectNow() throws IOException {
    int var1;
    try {
        var1 = this.selector.selectNow();
    } finally {
        if (this.wakenUp.get()) {
            this.selector.wakeup();
        }

    }

    return var1;
}

這裏就直接調用了JDK原生的selectNow方法。
之前說過的選擇策略:

public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
    return hasTasks ? selectSupplier.get() : -1;
}

其中hasTasks是根據hasTasks方法來判斷,而hasTasks方法就是判斷任務隊列是否爲空,那麼在一開始初始化,必然是空的,所以這裏calculateStrategy的返回值就是-1;

那麼case爲-1條件成立,執行this.select(this.wakenUp.getAndSet(false)),其中wakenUp是一個原子化的Boolean,用來表示是需要喚醒Selector的輪詢阻塞,初始化是爲true,這裏通過CAS操作設置爲false代表不需要喚醒,後面在select執行完後,又判斷wakenUp是否需要喚醒,說明在select中對Selector的阻塞進行了檢查,若是需要喚醒,就通過Selector的原生API完成喚醒【Java】NIO中Selector的select方法源碼分析

來看看這裏的select實現:

private void select(boolean oldWakenUp) throws IOException {
    Selector selector = this.selector;

    try {
        int selectCnt = 0;
        long currentTimeNanos = System.nanoTime();
        long selectDeadLineNanos = currentTimeNanos + this.delayNanos(currentTimeNanos);

        while(true) {
            long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;
            if (timeoutMillis <= 0L) {
                if (selectCnt == 0) {
                    selector.selectNow();
                    selectCnt = 1;
                }
                break;
            }

            if (this.hasTasks() && this.wakenUp.compareAndSet(false, true)) {
                selector.selectNow();
                selectCnt = 1;
                break;
            }

            int selectedKeys = selector.select(timeoutMillis);
            ++selectCnt;
            if (selectedKeys != 0 || oldWakenUp || this.wakenUp.get() || this.hasTasks() || this.hasScheduledTasks()) {
                break;
            }

            if (Thread.interrupted()) {
                if (logger.isDebugEnabled()) {
                    logger.debug("Selector.select() returned prematurely because Thread.currentThread().interrupt() was called. Use NioEventLoop.shutdownGracefully() to shutdown the NioEventLoop.");
                }

                selectCnt = 1;
                break;
            }

            long time = System.nanoTime();
            if (time - TimeUnit.MILLISECONDS.toNanos(timeoutMillis) >= currentTimeNanos) {
                selectCnt = 1;
            } else if (SELECTOR_AUTO_REBUILD_THRESHOLD > 0 && selectCnt >= SELECTOR_AUTO_REBUILD_THRESHOLD) {
                logger.warn("Selector.select() returned prematurely {} times in a row; rebuilding Selector {}.", selectCnt, selector);
                this.rebuildSelector();
                selector = this.selector;
                selector.selectNow();
                selectCnt = 1;
                break;
            }

            currentTimeNanos = time;
        }

        if (selectCnt > 3 && logger.isDebugEnabled()) {
            logger.debug("Selector.select() returned prematurely {} times in a row for Selector {}.", selectCnt - 1, selector);
        }
    } catch (CancelledKeyException var13) {
        if (logger.isDebugEnabled()) {
            logger.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector {} - JDK bug?", selector, var13);
        }
    }

}

這個方法雖然看着很長,但核心就是判斷這個存放任務的阻塞隊列是否還有任務,若是有,就直接調用Selector的selectNow方法獲取就緒的文件描述符,若是沒有就緒的文件描述符該方法也會立即返回;若是阻塞隊列中沒有任務,就調用Selector的select(timeout)方法,嘗試在超時時間內取獲取就緒的文件描述符。

因爲現在是在執行NioEventLoopGroup的創建,並沒有Channel的註冊,也就沒有輪詢到任何文件描述符就緒。
在輪詢結束後,回到run方法,進入default塊:
其中ioRatio是執行IO操作和執行任務隊列的任務用時比率,默認是50。若是ioRatio設置爲100,就必須等到tasks阻塞隊列中的所有任務執行完畢纔再次進行輪詢;若是小於100,那麼就根據(100 - ioRatio) / ioRatio的比值乘以ioTime計算出的超時時間讓所有任務嘗試在超時時間內執行完畢,若是到達超時時間還沒執行完畢,就在下一輪的輪詢中執行。

processSelectedKeys方法就是獲取Selector輪詢的SelectedKeys結果:

private void processSelectedKeys() {
    if (this.selectedKeys != null) {
        this.processSelectedKeysOptimized();
    } else {
        this.processSelectedKeysPlain(this.selector.selectedKeys());
    }

}

selectedKeys 在openSelector時被初始化過了,若是在openSelector中出現異常selectedKeys纔會爲null。

processSelectedKeysOptimized方法:

private void processSelectedKeysOptimized() {
    for(int i = 0; i < this.selectedKeys.size; ++i) {
        SelectionKey k = this.selectedKeys.keys[i];
        this.selectedKeys.keys[i] = null;
        Object a = k.attachment();
        if (a instanceof AbstractNioChannel) {
            this.processSelectedKey(k, (AbstractNioChannel)a);
        } else {
            NioTask<SelectableChannel> task = (NioTask)a;
            processSelectedKey(k, task);
        }

        if (this.needsToSelectAgain) {
            this.selectedKeys.reset(i + 1);
            this.selectAgain();
            i = -1;
        }
    }

}

這裏就通過遍歷在openSelector中注入進Selector的SelectedKeys,得到SelectionKey 對象。
在這裏可以看到Netty很巧妙地通過SelectionKey的attachment附件,將JDK中的Channel和Netty中的Channel聯繫了起來。
根據得到的附件Channel的類型,執行不同的processSelectedKey方法,去處理IO操作。

processSelectedKey(SelectionKey k, AbstractNioChannel ch)方法:

private void processSelectedKey(SelectionKey k, AbstractNioChannel ch) {
    NioUnsafe unsafe = ch.unsafe();
    if (!k.isValid()) {
        NioEventLoop eventLoop;
        try {
            eventLoop = ch.eventLoop();
        } catch (Throwable var6) {
            return;
        }

        if (eventLoop == this && eventLoop != null) {
            unsafe.close(unsafe.voidPromise());
        }
    } else {
        try {
            int readyOps = k.readyOps();
            if ((readyOps & 8) != 0) {
                int ops = k.interestOps();
                ops &= -9;
                k.interestOps(ops);
                unsafe.finishConnect();
            }

            if ((readyOps & 4) != 0) {
                ch.unsafe().forceFlush();
            }

            if ((readyOps & 17) != 0 || readyOps == 0) {
                unsafe.read();
            }
        } catch (CancelledKeyException var7) {
            unsafe.close(unsafe.voidPromise());
        }

    }
}

這裏的主要核心就是根據SelectedKey的readyOps值來判斷,處理不同的就緒事件,有如下幾種事件:

public static final int OP_READ = 1 << 0;
public static final int OP_WRITE = 1 << 2;
public static final int OP_CONNECT = 1 << 3;
public static final int OP_ACCEPT = 1 << 4;

結合來看上面的判斷就對應:連接就緒、寫就緒、偵聽或者讀就緒(或者缺省狀態0,該狀態是未來註冊時的默認狀態,後續博客會介紹),交由Netty的AbstractNioChannel的NioUnsafe去處理不同事件的byte數據,NioUnsafe會將數據再交由ChannelPipeline雙向鏈表去處理。
關於ChannelPipeline會在後續的博客中詳細介紹。

processSelectedKey(SelectionKey k, NioTask task)這個方法的實現細節需要由使用者實現NioTask接口,就不說了。

回到processSelectedKeys方法,在this.selectedKeys等於null的情況下:

private void processSelectedKeysPlain(Set<SelectionKey> selectedKeys) {
    if (!selectedKeys.isEmpty()) {
        Iterator i = selectedKeys.iterator();

        while(true) {
            SelectionKey k = (SelectionKey)i.next();
            Object a = k.attachment();
            i.remove();
            if (a instanceof AbstractNioChannel) {
                this.processSelectedKey(k, (AbstractNioChannel)a);
            } else {
                NioTask<SelectableChannel> task = (NioTask)a;
                processSelectedKey(k, task);
            }

            if (!i.hasNext()) {
                break;
            }

            if (this.needsToSelectAgain) {
                this.selectAgain();
                selectedKeys = this.selector.selectedKeys();
                if (selectedKeys.isEmpty()) {
                    break;
                }

                i = selectedKeys.iterator();
            }
        }

    }
}

這是在openSelector中注入進Selector的SelectedKeys失敗的情況下,直接遍歷Selector本身的SelectedKeys,和processSelectedKeysOptimized沒有差別。

繼續回到run方法,在調用完processSelectedKeys方法後,就需要調用runAllTasks處理任務隊列中的任務:
runAllTasks()方法:

protected boolean runAllTasks() {
    assert this.inEventLoop();

    boolean ranAtLeastOne = false;

    boolean fetchedAll;
    do {
        fetchedAll = this.fetchFromScheduledTaskQueue();
        if (this.runAllTasksFrom(this.taskQueue)) {
            ranAtLeastOne = true;
        }
    } while(!fetchedAll);

    if (ranAtLeastOne) {
        this.lastExecutionTime = ScheduledFutureTask.nanoTime();
    }

    this.afterRunningAllTasks();
    return ranAtLeastOne;
}

首先調用fetchFromScheduledTaskQueue方法:

private boolean fetchFromScheduledTaskQueue() {
    long nanoTime = AbstractScheduledEventExecutor.nanoTime();

    for(Runnable scheduledTask = this.pollScheduledTask(nanoTime); scheduledTask != null; scheduledTask = this.pollScheduledTask(nanoTime)) {
        if (!this.taskQueue.offer(scheduledTask)) {
            this.scheduledTaskQueue().add((ScheduledFutureTask)scheduledTask);
            return false;
        }
    }

    return true;
}

這裏就是通過pollScheduledTask不斷地從延時任務隊列獲取到期的任務,將到期的任務添加到taskQueue任務隊列中,爲上面的runAllTasksFrom執行做準備;若是添加失敗,再把它放進延時任務隊列。

pollScheduledTask方法:

protected final Runnable pollScheduledTask(long nanoTime) {
    assert this.inEventLoop();

    Queue<ScheduledFutureTask<?>> scheduledTaskQueue = this.scheduledTaskQueue;
    ScheduledFutureTask<?> scheduledTask = scheduledTaskQueue == null ? null : (ScheduledFutureTask)scheduledTaskQueue.peek();
    if (scheduledTask == null) {
        return null;
    } else if (scheduledTask.deadlineNanos() <= nanoTime) {
        scheduledTaskQueue.remove();
        return scheduledTask;
    } else {
        return null;
    }
}

從延時任務隊列中獲取隊首的任務scheduledTask,若是scheduledTask的deadlineNanos小於等於nanoTime,說明該任務到期。

回到runAllTasks,將到期了的延時任務放在了任務隊列,由runAllTasksFrom執行這些任務:

protected final boolean runAllTasksFrom(Queue<Runnable> taskQueue) {
    Runnable task = pollTaskFrom(taskQueue);
    if (task == null) {
        return false;
    } else {
        do {
            safeExecute(task);
            task = pollTaskFrom(taskQueue);
        } while(task != null);

        return true;
    }
}

不斷地從任務隊列隊首獲取任務,然後執行,直到沒有任務。

pollTaskFrom是獲取隊首任務:

protected static Runnable pollTaskFrom(Queue<Runnable> taskQueue) {
    Runnable task;
    do {
        task = (Runnable)taskQueue.poll();
    } while(task == WAKEUP_TASK);

    return task;
}

其中WAKEUP_TASK,是用來巧妙地控制循環:

private static final Runnable WAKEUP_TASK = new Runnable() {
    public void run() {
    }
};

safeExecute是執行任務:

protected static void safeExecute(Runnable task) {
    try {
        task.run();
    } catch (Throwable var2) {
        logger.warn("A task raised an exception. Task: {}", task, var2);
    }

}

實際上就是執行Runnable 的run方法。

繼續回到runAllTasks方法,當所有到期任務執行完畢後,根據ranAtLeastOne判斷是否需要修改最後一次執行時間lastExecutionTime,最後調用afterRunningAllTasks方法,該方法是在SingleThreadEventLoop中實現的:

protected void afterRunningAllTasks() {
    this.runAllTasksFrom(this.tailTasks);
}

這裏就僅僅執行了tailTasks隊列中的任務。runAllTasks到這裏執行完畢。

再來看看runAllTasks(timeoutNanos)方法:

protected boolean runAllTasks(long timeoutNanos) {
    this.fetchFromScheduledTaskQueue();
    Runnable task = this.pollTask();
    if (task == null) {
        this.afterRunningAllTasks();
        return false;
    } else {
        long deadline = ScheduledFutureTask.nanoTime() + timeoutNanos;
        long runTasks = 0L;

        long lastExecutionTime;
        while(true) {
            safeExecute(task);
            ++runTasks;
            if ((runTasks & 63L) == 0L) {
                lastExecutionTime = ScheduledFutureTask.nanoTime();
                if (lastExecutionTime >= deadline) {
                    break;
                }
            }

            task = this.pollTask();
            if (task == null) {
                lastExecutionTime = ScheduledFutureTask.nanoTime();
                break;
            }
        }

        this.afterRunningAllTasks();
        this.lastExecutionTime = lastExecutionTime;
        return true;
    }
}

這個方法前面的runAllTasks方法類似,先通過fetchFromScheduledTaskQueue將所有到期了的延時任務放在taskQueue中,然後不斷從taskQueue隊首獲取任務,但是,若是執行到了到超過了63個任務,判斷是否達到了超時時間deadline,若是達到結束循環,留着下次執行,反之繼續循環執行任務。

回到run方法,在輪詢完畢,並且執行完任務後,通過isShuttingDown判斷當前狀態,在之前的CAS操作中,state已經變爲了3,所以isShuttingDown成立,就需要調用closeAll方法:

private void closeAll() {
    this.selectAgain();
    Set<SelectionKey> keys = this.selector.keys();
    Collection<AbstractNioChannel> channels = new ArrayList(keys.size());
    Iterator var3 = keys.iterator();

    while(var3.hasNext()) {
        SelectionKey k = (SelectionKey)var3.next();
        Object a = k.attachment();
        if (a instanceof AbstractNioChannel) {
            channels.add((AbstractNioChannel)a);
        } else {
            k.cancel();
            NioTask<SelectableChannel> task = (NioTask)a;
            invokeChannelUnregistered(task, k, (Throwable)null);
        }
    }

    var3 = channels.iterator();

    while(var3.hasNext()) {
        AbstractNioChannel ch = (AbstractNioChannel)var3.next();
        ch.unsafe().close(ch.unsafe().voidPromise());
    }

}

在這裏首先調用selectAgain進行一次輪詢:

private void selectAgain() {
    this.needsToSelectAgain = false;

    try {
        this.selector.selectNow();
    } catch (Throwable var2) {
        logger.warn("Failed to update SelectionKeys.", var2);
    }

}

通過這次的輪詢,將當前仍有事件就緒的JDK的SelectionKey中綁定的Netty的Channel添加到channels集合中,遍歷這個集合,通過unsafe的close方法關閉Netty的Channel。

之後調用confirmShutdown方法:

protected boolean confirmShutdown() {
    if (!this.isShuttingDown()) {
        return false;
    } else if (!this.inEventLoop()) {
        throw new IllegalStateException("must be invoked from an event loop");
    } else {
        this.cancelScheduledTasks();
        if (this.gracefulShutdownStartTime == 0L) {
            this.gracefulShutdownStartTime = ScheduledFutureTask.nanoTime();
        }

        if (!this.runAllTasks() && !this.runShutdownHooks()) {
            long nanoTime = ScheduledFutureTask.nanoTime();
            if (!this.isShutdown() && nanoTime - this.gracefulShutdownStartTime <= this.gracefulShutdownTimeout) {
                if (nanoTime - this.lastExecutionTime <= this.gracefulShutdownQuietPeriod) {
                    this.wakeup(true);

                    try {
                        Thread.sleep(100L);
                    } catch (InterruptedException var4) {
                        ;
                    }

                    return false;
                } else {
                    return true;
                }
            } else {
                return true;
            }
        } else if (this.isShutdown()) {
            return true;
        } else if (this.gracefulShutdownQuietPeriod == 0L) {
            return true;
        } else {
            this.wakeup(true);
            return false;
        }
    }
}

首先調用cancelScheduledTasks,取消所有的延時任務:

protected void cancelScheduledTasks() {
    assert this.inEventLoop();

    PriorityQueue<ScheduledFutureTask<?>> scheduledTaskQueue = this.scheduledTaskQueue;
    if (!isNullOrEmpty(scheduledTaskQueue)) {
        ScheduledFutureTask<?>[] scheduledTasks = (ScheduledFutureTask[])scheduledTaskQueue.toArray(new ScheduledFutureTask[scheduledTaskQueue.size()]);
        ScheduledFutureTask[] var3 = scheduledTasks;
        int var4 = scheduledTasks.length;

        for(int var5 = 0; var5 < var4; ++var5) {
            ScheduledFutureTask<?> task = var3[var5];
            task.cancelWithoutRemove(false);
        }

        scheduledTaskQueue.clearIgnoringIndexes();
    }
}

遍歷scheduledTasks這個延時任務對立中所有的任務,通過cancelWithoutRemove將該任務取消。

至此輪詢的整個生命週期完成。

回到SingleThreadEventExecutor的doStartThread方法,在run方法執行完畢後,說明Selector輪詢結束,調用SingleThreadEventExecutor.this.cleanup()方法關閉Selector:

protected void cleanup() {
    try {
        this.selector.close();
    } catch (IOException var2) {
        logger.warn("Failed to close a selector.", var2);
    }

}

這次終於可以回到MultithreadEventExecutorGroup的構造,在children創建完畢後,用chooserFactory根據children的大小創建chooser,前面說過。

然後產生terminationListener異步中斷監聽對象,給每個NioEventLoop設置中斷監聽,然後對children進行了備份處理,通過readonlyChildren保存。

至此NioEventLoopGroup的創建全部結束。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章