Netty thread model preface

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.

Intelligent Recommendation

Netty features and thread model

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

013. NETTY thread model

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...

Netty thread model and basics

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...

Netty thread model and gameplay

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 ...

Netty - Thread Model Reactor

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...

More Recommendation

Netty thread model [next]

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...

【Netty】 thread model

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 -...

Netty entry thread model

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...

Redis source code parsing: 09redis database implementations (key operation, key timeout function key space notification)

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...

PAT B1041-B1045 Question

1、b1041 2、b1042 3、b1043 4、b1044 5、b1045...

Copyright  DMCA © 2018-2026 - All Rights Reserved - www.programmersought.com  User Notice

Top