文章目录

  • netty版本
  • Netty耗时任务的处理
  • 代码案例
    • `Handler`自定义业务线程池
    • Context中添加线程池

netty版本

  1. 使用的netty版本是io.netty:netty-all:4.1.33.Final

Netty耗时任务的处理

  1. Netty中EventLoop用来处理IO线程,因此handler中的耗时任务(比如数据库连接、远程调用等)不能在EventLoop里面执行。如果有耗时任务,需要将耗时任务添加到业务线程池中执行。
  2. 处理耗时任务的两种方式
    • Handler中加入线程池
    • Context中添加线程池
  3. 两种方式的对比
    • Handler中自定义业务线程池更加灵活,每个Handler都可以自己控制自己的业务线程池,对于非耗时的任务可以不使用业务线程池,直接在EventLoop线程中执行。
    • Context中添加线程池(Netty建议的方式),在pipeline中添加Handler的时候,添加一个业务线程池。这种方式Handler中的代码不需要做任何修改,但是整个Handler都交给业务线程池,无论是否是耗时任务都会加入到队列里,控制的粒度比较粗。
  4. 如果业务ChannelHandler处理逻辑比较简单,执行时间是受控的,业务I/O线程的负载也不重,在这种应用场景下,业务ChannelHandler可以和I/O操作共享同一个线程。使用这种线程模型会带来两个优势:
    • 开发简单,开发业务ChannelHandler的不需要关注Netty的线程模型
    • 性能更高:因为减少了一次线程上下文切换,所以性能会更高。
  5. Netty线程池的特点
    • ChannelEventLoopN:1的关系:一个Channel生命周期内只注册一个EventLoop,一个EventLoop可能会给分配给多个Channel,所以如果一个Channel阻塞可能会导致其他在同一个EventLoop上的Channel都阻塞。
    • 一个EventLoopGroup包含一个或者多个EventLoop,一个EventLoop在其生命周期内只与一个Thread绑定(EbeddedEventLoop除外)EventLoopThread负责处理该事件循环内所有的IO事件

代码案例

Handler自定义业务线程池

  1. Handler中自定义业务线程池

        @ChannelHandler.Sharablepublic class EchoServerHandler extends SimpleChannelInboundHandler<String> {public static final ChannelHandler INSTANCE = new EchoServerHandler();private static final String LINE = System.getProperty("line.separator");private EchoServerHandler() {}protected static ExecutorService newFixedThreadPool() {final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("netty-business-%d").setDaemon(false).build();return new ThreadPoolExecutor(200, 200,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(10000),threadFactory);}final static ListeningExecutorService service = MoreExecutors.listeningDecorator(newFixedThreadPool());@Overridepublic void channelRead0(ChannelHandlerContext ctx, String msg) {service.submit(new Runnable() {@Overridepublic void run() {//模拟耗时任务try {Thread.sleep(5000);logger.info("execute time 5s");} catch (InterruptedException e) {Thread.currentThread().interrupt();}ctx.writeAndFlush(msg + LINE).addListener(ChannelFutureListener.CLOSE);}});}}
    
  2. Server启动代码

        public class EchoServer {private final int port;public EchoServer(int port) {this.port = port;}public void start() throws Exception {NioEventLoopGroup boss = new NioEventLoopGroup(1);NioEventLoopGroup worker = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap();b.group(boss, worker).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new LineBasedFrameDecoder(1024));pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());pipeline.addLast(EchoServerHandler.INSTANCE);}});ChannelFuture f = b.bind().sync();System.out.println(String.format("%s started and listen on %s", EchoServer.class.getName(), f.channel().localAddress()));f.channel().closeFuture().sync();} finally {boss.shutdownGracefully().sync();worker.shutdownGracefully().sync();}}public static void main(String[] args) throws Exception {new EchoServer(8080).start();}}
    
  3. 使用多个telnet连接并请求,输出结果,可以看出执行任务使用的是我们自己定义的线程池

        netty-business-0 execute time 5snetty-business-1 execute time 5s
    

Context中添加线程池

  1. Handler代码无需任何的改动,不需要启动任何额外线程来处理任务

        @ChannelHandler.Sharablepublic class EchoServerHandler extends SimpleChannelInboundHandler<String> {public static final ChannelHandler INSTANCE = new EchoServerHandler();private static final String LINE = System.getProperty("line.separator");private EchoServerHandler() {}@Overridepublic void channelRead0(ChannelHandlerContext ctx, String msg) {//模拟耗时任务try {Thread.sleep(5000);System.out.printf("%s execute time 5s \n", Thread.currentThread().getName());} catch (InterruptedException e) {Thread.currentThread().interrupt();}ctx.writeAndFlush(msg + LINE).addListener(ChannelFutureListener.CLOSE);}}
  2. 启动代码

        public class EchoServer {private final int port;public EchoServer(int port) {this.port = port;}public void start() throws Exception {final ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("netty-context-business-%d").setDaemon(false).build();NioEventLoopGroup boss = new NioEventLoopGroup(1);NioEventLoopGroup worker = new NioEventLoopGroup();NioEventLoopGroup business = new NioEventLoopGroup(200,threadFactory);try {ServerBootstrap b = new ServerBootstrap();b.group(boss, worker).channel(NioServerSocketChannel.class).localAddress(new InetSocketAddress(port)).childHandler(new ChannelInitializer<SocketChannel>() {@Overridepublic void initChannel(SocketChannel ch) {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new LineBasedFrameDecoder(1024));pipeline.addLast(new StringDecoder());pipeline.addLast(new StringEncoder());pipeline.addLast(business, EchoServerHandler.INSTANCE);}});ChannelFuture f = b.bind().sync();System.out.println(String.format("%s started and listen on %s", EchoServer.class.getName(), f.channel().localAddress()));f.channel().closeFuture().sync();} finally {boss.shutdownGracefully().sync();worker.shutdownGracefully().sync();business.shutdownGracefully().sync();}}public static void main(String[] args) throws Exception {new EchoServer(8080).start();}}
  3. 使用多个telnet连接并请求,输出结果

        netty-context-business-0 execute time 5s netty-context-business-1 execute time 5s
    

Netty案例(二)之耗时任务的处理相关推荐

  1. 【Netty】Netty 入门案例分析 ( Netty 线程模型 | Netty 案例需求 | IntelliJ IDEA 项目导入 Netty 开发库 )

    文章目录 一. Netty 线程模型 二. Netty 案例需求 三. IntelliJ IDEA 引入 Netty 包 一. Netty 线程模型 1 . Netty 中的线程池 : Netty 中 ...

  2. 蚂蚁区块链投票案例(二)---投票合约设计开发

    文章目录 摘要 背景 案例场景 用例分析 系统管理员注册 添加小区.添加房屋 编辑房屋 发起投票 统计投票 业主注册 业主实名认证 客房关系认证 投票 合约设计 设计原则 合约设计 合约开发 命名规则 ...

  3. 2021年大数据Flink(三十五):​​​​​​​Table与SQL ​​​​​​案例二

    目录 案例二 需求 代码实现-SQL 代码实现-Table 案例二 需求 使用SQL和Table两种方式对DataStream中的单词进行统计 代码实现-SQL package cn.it.sql;i ...

  4. 2021年大数据Flink(二十):案例二 基于数量的滚动和滑动窗口

    目录 案例二 基于数量的滚动和滑动窗口 需求 代码实现 案例二 基于数量的滚动和滑动窗口 需求 需求1:统计在最近5条消息中,各自路口通过的汽车数量,相同的key每出现5次进行统计--基于数量的滚动窗 ...

  5. 2021年大数据Spark(三十七):SparkStreaming实战案例二 UpdateStateByKey

    目录 SparkStreaming实战案例二 UpdateStateByKey 需求 1.updateStateByKey 2.mapWithState 代码实现 SparkStreaming实战案例 ...

  6. 2021年大数据Spark(二十七):SparkSQL案例一花式查询和案例二WordCount

    目录 案例一:花式查询 案例二:WordCount 基于DSL编程 基于SQL编程 具体演示代码如下: 案例一:花式查询 package cn.itcast.sqlimport org.apache. ...

  7. 【数字信号处理】线性时不变系统 LTI “ 输入 “ 与 “ 输出 “ 之间的关系 ( 线性卷积计算案例二 | 计算 卷积 )

    文章目录 一.线性卷积计算 案例二 一.线性卷积计算 案例二 给定如下两个序列 : x(n)={3,4,5}[−2,0]x(n) = \{ 3 , 4, 5 \}_{[-2,0]}x(n)={3,4, ...

  8. 【数字信号处理】线性时不变系统 LTI ( 判断某个系统是否是 “ 非时变 “ 系统 | 案例二 )

    文章目录 一.判断系统是否 " 非时变 " 1.案例二 ① 时不变系统概念 ② 先变换后移位 ③ 先移位后变换 ④ 结论 一.判断系统是否 " 非时变 " 1. ...

  9. Redis简单案例(二) 网站最近的访问用户

    原文:Redis简单案例(二) 网站最近的访问用户 我们有时会在网站中看到最后的访问用户.最近的活跃用户等等诸如此类的一些信息.本文就以最后的访问用户为例, 用Redis来实现这个小功能.在这之前,我 ...

最新文章

  1. Windows驱动开发 - 设备对象初步学习
  2. 图解.net程序集赋予强名称
  3. CO模块之利润中心会计
  4. LintCode 550. 最常使用的K个单词II(自定义set(可修改数据的优先队列) + map)
  5. dart 怎么判断function的返回值为空_R 学习-第二章第二节- 尝试写个Function,超级菜鸟教程...
  6. eclipse常见小问题
  7. sudo uograde 之后 需要重装显卡驱动
  8. Linux shell笔记5 基本文本处理
  9. Linux实现倒计时显示时分QT,qt实现倒计时示例
  10. 微信公众号H5页面:禁止分享操作
  11. Win10的系统重装
  12. 爬虫案例——模拟登录QQ空间
  13. 英语语法新思维 总结 问答对形式
  14. 英语语法基础06(长难句训练)
  15. 国外7个免费的网络主机服务
  16. php微信公众号测试账号密码,微信公众号测试账号配置失败竟然是因为一个字符...
  17. vue简单实现吸顶效果pc
  18. Apache Commons-pool2使用入门
  19. GL calls GL verts FPS
  20. PL2303GR‎‎ ‎‎USB 转 RS485 桥接控制器‎

热门文章

  1. 客服回复话术100句
  2. 联想计算机怎么关机,联想笔记本怎么关机
  3. Unity CardboardSDK解析
  4. 2022 世界人工智能大会,都讲了些啥?
  5. English--定语从句
  6. 数据结构与算法33-PIPI捡垃圾
  7. 2021-2025年中国自动化侧面装载机行业市场供需与战略研究报告
  8. 设计如下类: 1) 建立一个Point类,表示平面中的一个点;建立一个Line类,表示平面中的一条线端, 内含两个Point类的对象;建立Triangle类,表示一个三角形
  9. NLP系列笔记:通俗理解LDA主题模型
  10. 使用PS制作旋转星空