您好,登錄后才能下訂單哦!
Netty代碼下載和編譯參考前一篇Netty文章
https://blog.51cto.com/483181/2112163
一般Netty服務器端這樣編寫
EventLoopGroup bossGroup = new NioEventLoopGroup(); //1. 實例化NioEventLoopGroup對象
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap(); //2.
b.group(bossGroup, workerGroup) //3.
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new FixedLengthFrameDecoder(20));
}
});
ChannelFuture f = b.bind(port).sync(); //4.
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
一步步來看,首先看第一個注釋,初始化NioEventLoopGroup對象
EventLoopGroup bossGroup = new NioEventLoopGroup(); //1. 實例化NioEventLoopGroup對象
下圖是NioEventLoopGroup的類繼承圖,包含類成員和方法,比較詳細。 這個功能是IntelliJ 自帶的。
右擊NioEventLoopGroup類名,選擇Diagrams->Show Diagram->上面有f,m的按鈕,分別對應field和method。
如下:
public NioEventLoopGroup() {
this(0);
}
public NioEventLoopGroup(int nThreads) {
this(nThreads, (Executor) null);
}
public NioEventLoopGroup(int nThreads, Executor executor) {
this(nThreads, executor, SelectorProvider.provider());
}
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
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());
}
我們可以看到幾點
private static SelectorProvider provider = null;
public static SelectorProvider provider() {
synchronized (lock) {
if (provider != null)
return provider;
return AccessController.doPrivileged(
new PrivilegedAction<SelectorProvider>() {
public SelectorProvider run() {
if (loadProviderFromProperty())
return provider;
if (loadProviderAsService())
return provider;
provider = sun.nio.ch.DefaultSelectorProvider.create();
return provider;
}
});
}
}
public class DefaultSelectorProvider {
private DefaultSelectorProvider() {
}
public static SelectorProvider create() {
return new KQueueSelectorProvider();
}
}
public class KQueueSelectorProvider extends SelectorProviderImpl {
public KQueueSelectorProvider() {
}
public AbstractSelector openSelector() throws IOException {
return new KQueueSelectorImpl(this);
}
}
這段代碼我們也可以看到幾點:
這個先記下來,也許后面分析會有用,繼續分析MultithreadEventLoopGroup的構造函數。
protected MultithreadEventLoopGroup(int nThreads, ThreadFactory threadFactory, Object... args) {
super(nThreads == 0 ? DEFAULT_EVENT_LOOP_THREADS : nThreads, threadFactory, args);
}
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"io.netty.eventLoopThreads", NettyRuntime.availableProcessors() * 2));
}
上面這段代碼我們可以看到這幾點:
繼續父類MultithreadEventExecutorGroup
protected MultithreadEventExecutorGroup(int nThreads, Executor executor,
EventExecutorChooserFactory chooserFactory, Object... args) {
...
children = new EventExecutor[nThreads]; //1. 實例化children數組
for (int i = 0; i < nThreads; i ++) { //2. 循環初始化children
boolean success = false;
try {
children[i] = newChild(executor, args);
success = true;
} catch (Exception e) {
throw new IllegalStateException("failed to create a child event loop", e);
} finally {
...
}
}
chooser = chooserFactory.newChooser(children); //3. 實例化chooser
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);
}
上面這段代碼可以從下面幾個點分析:
private final EventExecutor[] children;
protected EventLoop newChild(Executor executor, Object... args) throws Exception {
return new NioEventLoop(this, executor, (SelectorProvider) args[0],
((SelectStrategyFactory) args[1]).newSelectStrategy(), (RejectedExecutionHandler) args[2]);
}
NioEventLoop的繼承關系是這樣的,繼承于SingleThreadEventLoop,別忘了上面我們看到NioEventLoopGroup繼承自MultithreadEventLoopGroup.(看名字是單線程和多線程的區別?)
繼續看NioEventLoop的構造函數
NioEventLoop(NioEventLoopGroup parent, Executor executor, SelectorProvider selectorProvider,
SelectStrategy strategy, RejectedExecutionHandler rejectedExecutionHandler) {
super(parent, executor, false, DEFAULT_MAX_PENDING_TASKS, rejectedExecutionHandler);
provider = selectorProvider;
final SelectorTuple selectorTuple = openSelector();
selector = selectorTuple.selector;
unwrappedSelector = selectorTuple.unwrappedSelector;
selectStrategy = strategy;
}
private SelectorTuple openSelector() {
final Selector unwrappedSelector;
try {
unwrappedSelector = provider.openSelector();
} catch (IOException e) {
throw new ChannelException("failed to open a new selector", e);
}
if (DISABLE_KEYSET_OPTIMIZATION) {
return new SelectorTuple(unwrappedSelector);
}
...
}
從上面這段代碼我們可以看出這幾點
selector, unwrappedSelector是通過provider.openSelector()打開的.
根據2.3段的介紹,provider之前介紹的類型是KQueueSelectorProvider,然后它的openSelector會生成一個KQueueSelectorImpl
所以provider.openSelector()得到是KQueueSelectorImpl,KQueueSelectorImpl的繼承關系如下:
繼續往回看,看MultithreadEventExecutorGroup的構造函數。
EventExecutorChooserFactory.EventExecutorChooser chooser;
protected MultithreadEventExecutorGroup(int nThreads, Executor executor, Object... args) {
this(nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);
}
chooser = chooserFactory.newChooser(children);
上面代碼我們可以看到:
public EventExecutorChooser newChooser(EventExecutor[] executors) {
if (isPowerOfTwo(executors.length)) {
return new PowerOfTwoEventExecutorChooser(executors);
} else {
return new GenericEventExecutorChooser(executors);
}
}
public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory();
繼續看newChooser的實現
newChooser的代碼就不貼了,上面就有,從上面代碼可以看到:
private static boolean isPowerOfTwo(int val) {
return (val & -val) == val;
}
private static final class PowerOfTwoEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
PowerOfTwoEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[idx.getAndIncrement() & executors.length - 1];
}
}
private static final class GenericEventExecutorChooser implements EventExecutorChooser {
private final AtomicInteger idx = new AtomicInteger();
private final EventExecutor[] executors;
GenericEventExecutorChooser(EventExecutor[] executors) {
this.executors = executors;
}
@Override
public EventExecutor next() {
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
}
}
這種實現方法感覺比較優雅和高效,首先拿到-val,也就是val的二進制倒轉,然后+1。再做&運算。
大家自己可以拿到數字舉個例子,比較巧妙。后續自己寫代碼可以借鑒,這是讀源碼的一個好處,可以學習到別人很多優秀的寫法。
但是說實話,我沒有想到這兩種算法有什么區別,如果誰知道,請告訴我,謝謝。
return executors[idx.getAndIncrement() & executors.length - 1];
return executors[Math.abs(idx.getAndIncrement() % executors.length)];
繼續往回走,MultithreadEventExecutorGroup的構造函數就基本看完了。
我們來總結下NioEventLoopGroup的實例化過程,可以得到以下幾點。
1. NioEventLoopGroup的父類MultithreadEventExecutorGroup包含一個NioEventLoop數組children,數組的大小等于nThreads線程數目。如果沒有指定,默認一般是cpu核數 x 2
2. NioEventLoopGroup和NioEventLoop一樣都是繼承自Executor,但是NioEventLoopGroup又包含多個NioEventLoop(children數組),這種關系有點像android里面ViewGroup和View的關系。或者裝飾者模式?
3. NioEventLoopGroup繼承自MultithreadEventLoopGroup,而NioEventLoop繼承自SingleThreadEventLoop,從名字看,不知道和多線程,單線程有沒有關系。
4. MultithreadEventLoopGroup有個chooser,執行next方法的時候,會選擇下一個NioEventLoop對象,雖然并不知道兩個chooser算法有何區別。
5. NioEventLoopGroup里面重寫了newChild方法,里面實例化NioEventLoop。
6. NioEventLoop里面包含了Selector,類型是KQueueSelectorImpl
SelectorProvider provider
SelectStrategy selectStrategy
SelectStrategy這個我們上面我們沒有關注,其實它是NioEventLoopGroup構造函數傳進去的,如下:
public NioEventLoopGroup(
int nThreads, Executor executor, final SelectorProvider selectorProvider) {
this(nThreads, executor, selectorProvider, DefaultSelectStrategyFactory.INSTANCE);
}
public final class DefaultSelectStrategyFactory implements SelectStrategyFactory {
public static final SelectStrategyFactory INSTANCE = new DefaultSelectStrategyFactory();
private DefaultSelectStrategyFactory() { }
@Override
public SelectStrategy newSelectStrategy() {
return DefaultSelectStrategy.INSTANCE;
}
}
final class DefaultSelectStrategy implements SelectStrategy {
static final SelectStrategy INSTANCE = new DefaultSelectStrategy();
private DefaultSelectStrategy() { }
@Override
public int calculateStrategy(IntSupplier selectSupplier, boolean hasTasks) throws Exception {
return hasTasks ? selectSupplier.get() : SelectStrategy.SELECT;
}
}
所以SelectStrategy的實現類是DefaultSelectStrategy.
在理清楚NioEventLoopGroup實例化的過程之后,我們下一篇繼續按照源代碼分析Netty服務器端的源代碼。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。