tags: netty
This chapter introduces netty's threading model. Before talking about netty's threading model, we first write an example using Java's NIO to imitate netty's threading model.
Code address:GitHub code
The code structure is as follows:
We first look at the start class:
package com.cn;
import java.net.InetSocketAddress;
import java.util.concurrent.Executors;
import com.cn.pool.NioSelectorRunnablePool;
/**
* Start function
*
*/
public class Start {
public static void main(String[] args) {
//Initialize the thread
NioSelectorRunnablePool nioSelectorRunnablePool = new NioSelectorRunnablePool(Executors.newCachedThreadPool(), Executors.newCachedThreadPool());
//Get service class
ServerBootstrap bootstrap = new ServerBootstrap(nioSelectorRunnablePool);
//Binding port
bootstrap.bind(new InetSocketAddress(10101));
System.out.println("start");
}
}
The first step is to initialize the thread. At this time, two thread pools will be initialized: boss and worker. Take a look at the code:
package com.cn.pool;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import com.cn.NioServerBoss;
import com.cn.NioServerWorker;
/**
* selector thread manager
*
*/
public class NioSelectorRunnablePool {
/**
* Boss thread array
*/
private final AtomicInteger bossIndex = new AtomicInteger();
private Boss[] bosses;
/**
* Worker thread array
*/
private final AtomicInteger workerIndex = new AtomicInteger();
private Worker[] workeres;
public NioSelectorRunnablePool(Executor boss, Executor worker) {
initBoss(boss, 1);
initWorker(worker, Runtime.getRuntime().availableProcessors() * 2);
}
/**
* Initialize the boss thread
* @param boss
* @param count
*/
private void initBoss(Executor boss, int count) {
this.bosses = new NioServerBoss[count];
for (int i = 0; i < bosses.length; i++) {
bosses[i] = new NioServerBoss(boss, "boss thread " + (i+1), this);
}
}
/**
* Initialize worker thread
* @param worker
* @param count
*/
private void initWorker(Executor worker, int count) {
this.workeres = new NioServerWorker[count];
for (int i = 0; i < workeres.length; i++) {
workeres[i] = new NioServerWorker(worker, "worker thread " + (i+1), this);
}
}
/**
* Get a worker
* @return
*/
public Worker nextWorker() {
return workeres[Math.abs(workerIndex.getAndIncrement() % workeres.length)];
}
/**
* Get a boss
* @return
*/
public Boss nextBoss() {
return bosses[Math.abs(bossIndex.getAndIncrement() % bosses.length)];
}
}
The first step calls the constructor of NioSelectorRunnablePool. In the constructor, initBoss (Executor boss, int count) and initWorker (Executor worker, int count) are called. These two methods initialize NioServerBoss and NioServerWorker respectively.
Let's take a look at the code of NioServerBoss:
package com.cn;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.Executor;
import com.cn.pool.Boss;
import com.cn.pool.NioSelectorRunnablePool;
import com.cn.pool.Worker;
/**
* boss implementation class
*
*/
public class NioServerBoss extends AbstractNioSelector implements Boss{
public NioServerBoss(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
super(executor, threadName, selectorRunnablePool);
}
@Override
protected void process(Selector selector) throws IOException {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
if (selectedKeys.isEmpty()) {
return;
}
for (Iterator<SelectionKey> i = selectedKeys.iterator(); i.hasNext();) {
SelectionKey key = i.next();
i.remove();
ServerSocketChannel server = (ServerSocketChannel) key.channel();
// New client
SocketChannel channel = server.accept();
// set to non-blocking
channel.configureBlocking(false);
// Get a worker
Worker nextworker = getSelectorRunnablePool().nextWorker();
// Register new client access task
nextworker.registerNewChannelTask(channel);
System.out.println("New Client Link");
}
}
public void registerAcceptChannelTask(final ServerSocketChannel serverChannel){
final Selector selector = this.selector;
registerTask(new Runnable() {
@Override
public void run() {
try {
//Register serverChannel to selector
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (ClosedChannelException e) {
e.printStackTrace();
}
}
});
}
@Override
protected int select(Selector selector) throws IOException {
return selector.select();
}
}
The construction method of NioServerBoss inherits the construction method of AbstractNioSelector. Later we will see that AbstractNioSelector is actually a thread that implements the Runnable interface. We first follow the line to initialize the boss down. From the construction method of NioServerBoss, the super method starts to go down. Now look at the code of AbstractNioSelector:
package com.cn;
import java.io.IOException;
import java.nio.channels.Selector;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicBoolean;
import com.cn.pool.NioSelectorRunnablePool;
/**
* Abstract selector thread class
*
*
*/
public abstract class AbstractNioSelector implements Runnable {
/**
* Thread Pool
*/
private final Executor executor;
/**
* Selector
*/
protected Selector selector;
/**
* Selector wakeUp status flag
*/
protected final AtomicBoolean wakenUp = new AtomicBoolean();
/**
* Task queue
*/
private final Queue<Runnable> taskQueue = new ConcurrentLinkedQueue<Runnable>();
/**
* Thread name
*/
private String threadName;
/**
* Thread management objects
*/
protected NioSelectorRunnablePool selectorRunnablePool;
AbstractNioSelector(Executor executor, String threadName, NioSelectorRunnablePool selectorRunnablePool) {
this.executor = executor;
this.threadName = threadName;
this.selectorRunnablePool = selectorRunnablePool;
openSelector();
}
/**
* Get the selector and start the thread
*/
private void openSelector() {
try {
this.selector = Selector.open();
System.out.println("Selector open");
} catch (IOException e) {
throw new RuntimeException("Failed to create a selector.");
}
executor.execute(this);
}
@Override
public void run() {
Thread.currentThread().setName(this.threadName);
System.out.println(Thread.currentThread().getName()+"Thread run method");
while (true) {
try {
wakenUp.set(false);
select(selector);
processTaskQueue();
process(selector);
} catch (Exception e) {
// ignore
}
}
}
/**
* Register a task and activate the selector
*
* @param task
*/
protected final void registerTask(Runnable task) {
taskQueue.add(task);
Selector selector = this.selector;
if (selector != null) {
if (wakenUp.compareAndSet(false, true)) {
selector.wakeup();
}
} else {
taskQueue.remove(task);
}
}
/**
* Execute tasks in the queue
*/
private void processTaskQueue() {
for (;;) {
final Runnable task = taskQueue.poll();
if (task == null) {
break;
}
task.run();
}
}
/**
* Get thread management objects
* @return
*/
public NioSelectorRunnablePool getSelectorRunnablePool() {
return selectorRunnablePool;
}
/**
* select abstract method
*
* @param selector
* @return
* @throws IOException
*/
protected abstract int select(Selector selector) throws IOException;
/**
* Business processing of selector
*
* @param selector
* @throws IOException
*/
protected abstract void process(Selector selector) throws IOException;
}
We found that the method of initializing the boss thread pool is to finally obtain the selector and start the thread. The process() method has different implementation methods in the boss and worker implementation classes. It can be seen from the NioServerBoss code that the process method is to process the key of the Selector, mainly to create a new connection. And register the new client access task.
The method behind start is to get the service class and bind the port. Specifically, you need to take the code down and debug it step by step. I can only give a rough idea here. This thread model is basically the same as the processing in the source code. Let's run and see:
can accept connections and input from multiple clients. Only the client's telnet appears garbled.
This chapter first analyzes here, still need to look at the code, this code is equivalent to a simple netty implementation, which is good for understanding the netty source code later.
Zero copy hard driver - kernel buffer - protocol engine only DMA copy avoids cpu copy There was actually a cpu copy of kernel buffer - socket buffer, but the copied information can rarely be ignored; ...
Introduction to Netty Netty is a high-performance, high-scalable asynchronous event-driven network application framework, which greatly simplifies network programming such as TCP and UDP clients and s...
Why use Netty Netty is an asynchronous event-driven web application framework for rapid development of maintainable high-performance and high-profile servers and clients. Netty has the advantages of h...
Event cycle group All I / O operations in Netty are asynchronous, and the asynchronous execution results are obtained by channelfuture. Asynchronously executes a thread pool EventLoopGroup, it ...
table of Contents Thread model 1, traditional IO service model 2, Reactor mode reactor Three modes: to sum up Netty model Excommissum Thread model 1, traditional IO service model Blocked IO mode Get i...
Hey everyone, I amJava small white 2021。 The programmer of the halfway is in the development of aircraft, and the opportunity to find a more interesting thing under the development of a surveying cour...
content 1. Single Reactor single thread 2. Single Reactor Multi -thread 3. Reactor Main Strike Model Single -threaded model (single Reactor single thread) Multi -threaded model (single Reactor multi -...
Single-threaded model: the boss thread is responsible for connection and data reading and writing Hybrid model: the boss thread is responsible for connection and data reading and writing, and the work...
This chapter of the Redis database server implementations are introduced, indicating achieve Redis database-related operations, including key-value pairs in the database to add, delete, view, update a...
1、b1041 2、b1042 3、b1043 4、b1044 5、b1045...