Why event loop uses more than one thread?

Tags: ,



I always thought that asynchronous execution is about efficient resource utilization and thread safety, but today I ran into Netty’s strange behavior.

public class Example {
    public static void main(String[] args) throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap();
        try {
            bootstrap.group(group)
                     .channel(NioServerSocketChannel.class)
                     .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel channel) {
                            channel.pipeline()
                                   .addLast(new ChannelOutboundHandlerAdapter() {
                                        @Override
                                        public void read(ChannelHandlerContext ctx) {
                                            String id = String.valueOf(Thread.currentThread().getId());
                                            ctx.writeAndFlush(Unpooled.wrappedBuffer(id.getBytes(StandardCharsets.UTF_8)))
                                               .addListener(ChannelFutureListener.CLOSE);
                                            }
                                        });
                        }
                    })
                    .bind("localhost", 1234)
                    .sync()
                    .channel()
                    .closeFuture()
                    .syncUninterruptibly();
        } finally {
            group.shutdownGracefully()
                 .syncUninterruptibly();
        }
    }
}

When I connected for the first time, I got 16. Then 17, 18, 19, etc. Every connection was executed on a new thread! Why? What’s the point of Netty, if it’s multi-threaded?

Answer

NioEventLoopGroup uses worker threads to utilize multiple CPU cores. As per the no-argument constructor javadoc:

NioEventLoopGroup()

Create a new instance using the default number of threads, the default ThreadFactory and the SelectorProvider which is returned by SelectorProvider.provider().

The deafult thread count as per MultithreadEventLoopGroup will be twice the number of available processors:

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

Generally this should be enough to saturate the CPU without creating a huge number of threads. Spawn too few threads and you won’t get full CPU utilization. Spawn too many and you will waste substantial time context switching between them.



Source: stackoverflow