nettynettyandroid技术

Netty 异步线程池处理任务

2020-07-05  本文已影响0人  马路边的小破孩

前提

在Netty中做耗时的,不可预料的操作,比如数据库的操作,网络请求等,会严重影响Netty对Socket的处理速度。

解决方式

解决方式就是将耗时任务添加到异步线程池当中。就添加线程池这部操作来说,有2种方式:

1. handler中加入线程池

Server端代码:

public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap().group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new StringDecoder())
                                .addLast(new TaskHandler())                              
                        ;
                    }
                });
        try {
            ChannelFuture channelFuture = bootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }

    }

TaskHandler 代码:

public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //在handler中处理耗时任务
        System.out.println("当前handler处理线程名称:"+Thread.currentThread().getName());

        ctx.channel().eventLoop().submit(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5000L);
                    System.out.println("当前异步任务线程名称:"+Thread.currentThread().getName());
                    ctx.channel().writeAndFlush(Unpooled.copiedBuffer("hello~客户端".getBytes()));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        super.channelActive(ctx);
    }

运行打印输出结果:

当前handler处理线程名称:nioEventLoopGroup-3-2
当前异步任务线程名称:nioEventLoopGroup-3-2

2. Context中添加线程池

Netty为我们提供了一个线程池EventExecutorGroup的接口及其很多实现类,下面我们使用DefaultEventExecutorGroup 线程池异步处理任务,来对比一下 handler中异步线程执行任务的区别。

不加入DefaultEventExecutorGroup

Server端代码:

public static void main(String[] args) {
        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap().group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new StringDecoder())
                                .addLast(new TaskHandler())                             
                        ;
                    }
                });
        try {
            ChannelFuture channelFuture = bootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

TaskHandler代码:

 @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //在handler中处理耗时任务
        System.out.println("当前handler处理线程名称:"+Thread.currentThread().getName());
        super.channelActive(ctx);
    }

运行输出执行结果(运行三个客户端):

当前handler处理线程名称:nioEventLoopGroup-4-1
当前handler处理线程名称:nioEventLoopGroup-4-2
当前handler处理线程名称:nioEventLoopGroup-4-3

加入DefaultEventExecutorGroup

Server端代码:

 public static void main(String[] args) {
        DefaultEventExecutorGroup eventExecutors = new DefaultEventExecutorGroup(4);

        NioEventLoopGroup boss = new NioEventLoopGroup();
        NioEventLoopGroup worker = new NioEventLoopGroup();
        ServerBootstrap bootstrap = new ServerBootstrap().group(boss, worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel socketChannel) throws Exception {
                        socketChannel.pipeline()
                                .addLast(new StringDecoder())
                                //如果在handler前有添加EventExecutorGroup
                                //则该handler会优先添加到该线程池中
                                .addLast(eventExecutors,new TaskHandler())
                        ;
                    }
                });
        try {
            ChannelFuture channelFuture = bootstrap.bind(8080).sync();
            channelFuture.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            boss.shutdownGracefully();
            worker.shutdownGracefully();
        }
    }

Client端代码不变,和上面保持一致。
输出打印结果(运行三个客户端):

当前handler处理线程名称:defaultEventExecutorGroup-2-1
当前handler处理线程名称:defaultEventExecutorGroup-2-2
当前handler处理线程名称:defaultEventExecutorGroup-2-3

对比我们可以看出来,如果在handler前有添加DefaultEventExecutorGroup , 则该handler会优先添加到该线程池中,处理任务的线程池不在是NioEventLoopGroup。

3.两种方式比较

1.第一种方式在handler中添加异步,可能更加的自由,比如如果需要访问数据库,那我就异步,如果不需要就不异步,异步会拖长接口响应时间。因为需要将任务放进task中,如果IO时间很短,task很多,可能一个循环下来,都没时间执行整个task,导致响应时间不达标。

  1. 第二中方式是Netty标准方式即加入到队列,但是这么做会将整个handler都交给业务线程池,不论耗时不耗时都加入队列,不够灵活。
    3.各有优劣,灵活性来说,第一种好。
上一篇下一篇

猜你喜欢

热点阅读