Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

fifty-six。 Netty source code analysis-server initialization NioEventLoopGroup instantiation

2025-04-02 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/03 Report--

one。 Code download

Netty code download and compilation refer to the previous Netty article

Https://blog.51cto.com/483181/2112163

two。 Server code analysis 2.1 Server code writing

Generally, the Netty server side writes like this.

EventLoopGroup bossGroup = new NioEventLoopGroup () / / 1. Instantiate the NioEventLoopGroup object EventLoopGroup workerGroup = new NioEventLoopGroup (); try {ServerBootstrap b = new ServerBootstrap () / / 2. B.group (bossGroup, workerGroup) / / 3. Channel (NioServerSocketChannel.class) .option (ChannelOption.SO_BACKLOG ) .handler (new LoggingHandler (LogLevel.INFO)) .childHandler (new ChannelInitializer () {@ 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 () } 2.2 NioEventLoopGroup2.2.1 NioEventLoopGroup inheritance relationship

Step by step, first look at the first comment, initializing the NioEventLoopGroup object

EventLoopGroup bossGroup = new NioEventLoopGroup () / / 1. Instantiate NioEventLoopGroup object

The following figure is the class inheritance diagram of NioEventLoopGroup, which contains class members and methods in more detail. This feature is built into IntelliJ.

Right-click the name of the NioEventLoopGroup class, and select Diagrams- > Show Diagram- > the button with fMagne m on it, corresponding to field and method, respectively.

As follows:

2.2.2 NioEventLoopGroup constructor 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 ();}

What time can we see?

NioEventLoopGroup adopts the method of constructor overloading to adapt to different initialization scenarios. Executor passes nullSelectorProvider using SelectorProvider.provider (), and then passes all the constructed parameters to the parent class MultithreadEventLoopGroup (see the inheritance relationship above) 2.2.3 SelectorProvider.provider () private static SelectorProvider provider = null;public static SelectorProvider provider () {synchronized (lock) {if (provider! = null) return provider Return AccessController.doPrivileged (new PrivilegedAction () {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);}}

We can also see a few points in this code:

SelectorProvider provider is a singleton, an implementation of static type SelectorProvider.provider, which produces an openSelector of KQueueSelectorProviderKQueueSelectorProvider and generates a KQueueSelectorImpl.

Write this down first, and maybe later analysis will be useful, and continue to analyze the constructor of MultithreadEventLoopGroup.

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

We can see the following points in the above code:

If we instantiate NioEventLoopGroup with no parameters passed in, that is, no nThreads, then the default DEFAULT_EVENT_LOOP_THREADS will be used

If DEFAULT_EVENT_LOOP_THREADS is not configured with io.netty.eventLoopThreads, usually the instantiation method of cpu core * 2MultithreadEventLoopGroup is to continue to call the initialization method of the parent class.

Continue parent class MultithreadEventExecutorGroup

2.2.5 MultithreadEventExecutorGroupprotected MultithreadEventExecutorGroup (int nThreads, Executor executor, EventExecutorChooserFactory chooserFactory, Object... Args) {... Children = new EventExecutor [nThreads]; / / 1. Instantiate the children array 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 terminationListener = new FutureListener() { @Override public void operationComplete(Future future) throws Exception { if (terminatedChildren.incrementAndGet() == children.length) { terminationFuture.setSuccess(null); } } }; for (EventExecutor e: children) { e.terminationFuture().addListener(terminationListener); } Set childrenSet = new LinkedHashSet(children.length); Collections.addAll(childrenSet, children); readonlyChildren = Collections.unmodifiableSet(childrenSet); } 上面这段代码可以从下面几个点分析: private final EventExecutor[] children;children - EventExecutor数组,大小是nThreads,线程数目。newChild初始化 实例类是NioEventLoopGroup.java,返回NioEventLoop对象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的构造函数 2.2.6 NioEventLoopNioEventLoop(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); } ...} 从上面这段代码我们可以看出这几点 NioEventLoop里面保存了SelectorProvider selectorProvider, Selector selector, unwrappedSelector(类型是KQueueSelectorImpl) selector, unwrappedSelector是通过provider.openSelector()打开的. 根据2.3段的介绍,provider之前介绍的类型是KQueueSelectorProvider,然后它的openSelector会生成一个KQueueSelectorImpl 所以provider.openSelector()得到是KQueueSelectorImpl,KQueueSelectorImpl的继承关系如下:

Go back and look at the constructor of MultithreadEventExecutorGroup.

2.2.7 newChooserEventExecutorChooserFactory.EventExecutorChooser chooser;protected MultithreadEventExecutorGroup (int nThreads, Executor executor, Object... Args) {this (nThreads, executor, DefaultEventExecutorChooserFactory.INSTANCE, args);} chooser = chooserFactory.newChooser (children)

We can see the above code:

The type of chooserFactory is DefaultEventExecutorChooserFactory, so newChooser calls the DefaultEventExecutorChooserFactory.newChooser method.

As follows: public EventExecutorChooser newChooser (EventExecutor [] executors) {if (isPowerOfTwo (executors.length)) {return new PowerOfTwoEventExecutorChooser (executors);} else {return new GenericEventExecutorChooser (executors);}} the parameter passed is children, that is, the NioEventLoop array DefaultEventExecutorChooserFactory INSTANCE is an object of type static final, which is a singleton pattern of hungry Han style, as follows: public static final DefaultEventExecutorChooserFactory INSTANCE = new DefaultEventExecutorChooserFactory ()

Continue to look at the implementation of newChooser

2.2.8 newChooser

The newChooser code is not posted, it is on it, as can be seen from the code above:

IsPowerOfTwo is used to determine whether an integer is a power of 2, such as (2 return 4, 8 executors; PowerOfTwoEventExecutorChooser 16 executors; PowerOfTwoEventExecutorChooser 32, etc.). It is implemented as follows: 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)];}}

This implementation feels elegant and efficient, starting with-val, the binary inversion of val, and then + 1. Do the operation again.

You can get the numbers by yourself. for example, it's more ingenious. Later, you can learn from writing your own code, which is an advantage of reading the source code, and you can learn a lot of excellent writing methods from others.

The difference between PowerOfTwoEventExecutorChooser and GenericEventExecutorChooser is that the algorithm of the next method is different. The function is to select a NioEventLoop object from the NioEventLoop array.

But to be honest, I didn't think there was any difference between the two algorithms. If anyone knows, please let me know. Thank you.

Return executors [idx.getAndIncrement () & executors.length-1]; return executors [Math.abs (idx.getAndIncrement ()% executors.length)]

Keep going back, and you're almost done with the MultithreadEventExecutorGroup constructor.

three。 Summary

Let's summarize the instantiation process of NioEventLoopGroup and get the following points.

1. The parent class of NioEventLoopGroup, MultithreadEventExecutorGroup, contains an NioEventLoop array children, the size of which is equal to the number of nThreads threads. If not specified, the default is generally cpu core x 2

2. NioEventLoopGroup, like NioEventLoop, inherits from Executor, but NioEventLoopGroup also contains multiple NioEventLoop (children array), which is a bit like the relationship between ViewGroup and View in android. Or decorator mode?

3. NioEventLoopGroup inherits from MultithreadEventLoopGroup, while NioEventLoop inherits from SingleThreadEventLoop. From the name, I don't know if it has anything to do with multithreading or single threading.

4. MultithreadEventLoopGroup has a chooser, and when you execute the next method, you select the next NioEventLoop object, although you don't know the difference between the two chooser algorithms.

5. The newChild method is rewritten in NioEventLoopGroup to instantiate NioEventLoop.

6. NioEventLoop contains Selector and the type is KQueueSelectorImpl

SelectorProvider provider

SelectStrategy selectStrategy

We didn't pay attention to SelectStrategy above, but it was passed in by the NioEventLoopGroup constructor, as follows:

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

So the implementation class of SelectStrategy is DefaultSelectStrategy.

After figuring out the process of instantiating NioEventLoopGroup, let's move on to analyzing the Netty server-side source code according to the source code.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report