任务队列中的Task有3种典型使用场景

  1. 用户程序自定义的普通任务

    • 此前代码: 参考https://www.cnblogs.com/ronnieyuan/p/12016712.html

    • NettyServerHandler代码有改动:

      package com.ronnie.netty.sample;
      
      import io.netty.buffer.ByteBuf;
      import io.netty.buffer.Unpooled;
      import io.netty.channel.Channel;
      import io.netty.channel.ChannelHandlerContext;
      import io.netty.channel.ChannelInboundHandlerAdapter;
      import io.netty.channel.ChannelPipeline;
      import io.netty.util.CharsetUtil; /**
      * 1. 自定义一个Handler需要继承 netty 规定好的某个 HandlerAdapter(适配器模式)
      * 2. 这时我们自定义一个Handler, 才能称为一个handler
      */
      public class NettyServerHandler extends ChannelInboundHandlerAdapter { /**
      * 读取数据事件(这里我们可以读取客户端发送的消息)
      * ChannelHandlerContext ctx: 上下文对象, 含有管道 pipeline, 通道 channel, 地址 address
      * Object msg: 就是客户端发送的数据 默认Object
      * @param ctx
      * @param msg
      * @throws Exception
      */
      @Override
      public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { /* 比如这里我们有一个非常耗时的业务 -> 异步执行 -> 提交该channel对应的
      NioEventLoop 的 taskQueue中
      */ // 解决方案1: 用户程序自定义的普通任务
      ctx.channel().eventLoop().execute(new Runnable() {
      @Override
      public void run() {
      try {
      Thread.sleep(10 * 1000);
      ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, client, atme ", CharsetUtil.UTF_8));
      } catch (InterruptedException e) {
      System.out.println("Exception occurs: " + e.getMessage());
      }
      }
      });
      ctx.channel().eventLoop().execute(new Runnable() {
      @Override
      public void run() {
      try {
      Thread.sleep(20 * 1000);
      ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, client, yang ", CharsetUtil.UTF_8));
      } catch (InterruptedException e) {
      System.out.println("Exception occurs: " + e.getMessage());
      }
      }
      }); // Thread.sleep(10 * 1000);
      // ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, client, atme ", CharsetUtil.UTF_8)); System.out.println("go on ...");
      // System.out.println("The server is reading thread: " + Thread.currentThread().getName());
      // System.out.println("server ctx = " + ctx);
      // System.out.println("Check the relationship between channel and pipeline");
      // Channel channel = ctx.channel();
      // ChannelPipeline pipeline = ctx.pipeline(); // 本质是一个双向链表, 涉及到出栈入栈问题
      // // 将 msg转成一个 ByteBuf(是netty提供的, 不是NIO的 ByteBuffer, 性能更高)
      // ByteBuf buf = (ByteBuf) msg;
      // System.out.println("The message that client send: " + buf.toString(CharsetUtil.UTF_8));
      // System.out.println("The address of client: " + ctx.channel().remoteAddress());
      } /**
      * 数据读取完毕
      * @param ctx
      * @throws Exception
      */
      @Override
      public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { // write + flush, 将数据写入到缓冲并刷新
      // 一般来说, 我们对发送的数据进行编码
      ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, dear client, Kappa", CharsetUtil.UTF_8)); } /**
      * 处理异常, 一般需要关闭通道
      * @param ctx
      * @param cause
      * @throws Exception
      */
      @Override
      public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
      ctx.close();
      }
      }
    • 打上断点,debug启动

      • 左键点击ctx

        • pipeline -> channel -> eventLoop -> taskQueue

        • 可以看到两个线程任务存入了任务队列中

  2. 用户自定义定时任务

    • 在NettyServerHandler中之前添加的任务线程代码之下, 打印go on之前添加以下代码:

              // 用户自定义定时任务 -> 该任务是提交到 scheduleTaskQueue中的
      ctx.channel().eventLoop().schedule(new Runnable() {
      @Override
      public void run() {
      try {
      Thread.sleep(20 * 1000);
      ctx.writeAndFlush(Unpooled.copiedBuffer("Hello, client, yyf ", CharsetUtil.UTF_8));
      } catch (InterruptedException e) {
      System.out.println("Exception occurs: " + e.getMessage());
      }
      }
      }, 5, TimeUnit.SECONDS);
    • 打上断点, debug启动

      • 左键点击ctx

        • pipeline -> channel -> eventLoop -> taskQueue

        • 你会发现taskQueue中只有2个线程任务

        • 我们刚刚写的那个任务在scheduledTaskQueue中(pipeline -> channel -> eventLoop -> scheduledTaskQueue)

  3. 非当前Reactor 线程调用Channel的各种方法

    • 例如在推送系统的业务线程中, 根据用户的标识, 找到对应的Channel引用, 然后调用 Write 类方法向该用户推送消息, 就会进入到这种场景。最终的Write会提交到任务队列中后被异步消费。

Netty 方案再说明

  1. Netty 抽象出两组线程池, BossGroup 专门负责接收客户端连接, WorkerGroup 专门负责网络读写操作。
  2. NioEventLoop表示一个不断循环执行处理任务的线程, 每个 NioEventLoop都有一个selector, 用于监听绑定在其上的socket网络通道。
  3. NioEventLoop内部采用串行化设计, 从消息的读取 -> 解码 -> 处理 -> 编码 -> 发送, 始终由 IO 线程 NioEventLoop 负责
    • NioEventLoopGroup下包含多个NioEventLoop
    • 每个NioEventLoop 中包含有一个Selector, 一个 taskQueue
    • 每个NioEventLoop 中的 Selector 上可以注册监听多个 NioChannel
    • 每个NioChannel 只会绑定在唯一的NioEventLoop上
    • 每个NioChannel 都绑定有一个自己的 ChannelPipline

Netty 中队列的使用的更多相关文章

  1. Netty中的基本组件及关系

    原文:https://blog.csdn.net/summerZBH123/article/details/79344226---------------------  概述    这篇文章主要是用来 ...

  2. Netty 中ChannelOption的含义以及使用的场景

    Netty 中ChannelOption的含义以及使用的场景 转自:http://www.cnblogs.com/googlemeoften/p/6082785.html 1.ChannelOptio ...

  3. Netty中的那些坑

    Netty中的那些坑(上篇) 最近开发了一个纯异步的redis客户端,算是比较深入的使用了一把netty.在使用过程中一边优化,一边解决各种坑.儿这些坑大部分基本上是Netty4对Netty3的改进部 ...

  4. netty中的EventLoop和EventLoopGroup

    Netty框架的主要线程就是I/O线程,线程模型设计的好坏,决定了系统的吞吐量.并发性和安全性等架构质量属性. 一.Netty的线程模型 在讨论Netty线程模型时候,一般首先会想到的是经典的Reac ...

  5. Netty中NioEventLoopGroup的创建源码分析

    NioEventLoopGroup的无参构造: public NioEventLoopGroup() { this(0); } 调用了单参的构造: public NioEventLoopGroup(i ...

  6. netty中的发动机--EventLoop及其实现类NioEventLoop的源码分析

    EventLoop 在之前介绍Bootstrap的初始化以及启动过程时,我们多次接触了NioEventLoopGroup这个类,关于这个类的理解,还需要了解netty的线程模型.NioEventLoo ...

  7. Java网络编程 -- Netty中的ByteBuf

    由于JDK中提供的ByteBuffer无法动态扩容,并且API使用复杂等原因,Netty中提供了ByteBuf.Bytebuf的API操作更加便捷,可以动态扩容,提供了多种ByteBuf的实现,以及高 ...

  8. Netty 中的心跳检测机制

    心跳检测一般存在于建立长连接 或者 需要保活的场景. 心跳的使用场景 长连接的应用场景非常的广泛,比如监控系统,IM系统,即时报价系统,推送服务等等.像这些场景都是比较注重实时性,如果每次发送数据都要 ...

  9. Netty中的一些注意事项--底层基础

    转载自http://www.mamicode.com/info-detail-1215305.html 最近开发了一个纯异步的redis客户端,算是比较深入的使用了一把netty.在使用过程中一边优化 ...

随机推荐

  1. Spring源码试读--BeanFactory模拟实现

    动机 现在Springboot越来越便捷,如果简单的Spring应用,已无需再配置xml文件,基本可以实现全注解,即使是SpringCloud的那套东西,也都可以通过yaml配置完成.最近一年一直在用 ...

  2. tensorflow中的图(02-1)

    由于tensorflow版本迭代较快且不同版本的接口会有差距,我这里使用的是1.14.0的版本 安装指定版本的方法:pip install tensorflow==1.14.0      如果你之前安 ...

  3. HDU 5565:Clarke and baton

    Clarke and baton  Accepts: 14  Submissions: 79  Time Limit: 12000/6000 MS (Java/Others)  Memory Limi ...

  4. Webshell免杀研究

    前言 不想当将军的士兵不是好士兵,不想getshell的Hacker不是好Hacker~有时候我们在做攻防对抗时经常会碰到可以上传webshell的地方,但是经常会被安全狗.D盾.护卫神.云锁等安全软 ...

  5. cookie、session、localStorage、sessionStorage的区别

    cookie的机制 cookie是存储在用户本地终端上的数据.有时也用cookies,指某些网站为了辨别用户身份,进行session跟踪而存储在本地终端上的数据,通常经过加密. Cookie是服务器发 ...

  6. springcloud-zuul进阶篇

    一 前言 经过zuul初级篇(博客或者公主号springcloud专栏可以找到)的学习,读者都懂得如何简单的使用zuul进行路由网关配置,在进阶篇中你将获得zuul核心功能过滤器的基本使用,通过zuu ...

  7. 深入理解Java虚拟机-如何利用VisualVM对高并发项目进行性能分析

    前面在学习JVM的知识的时候,一般都需要利用相关参数进行分析,而分析一般都需要用到一些分析的工具,因为一般使用IDEA,而VisualVM对于IDEA也不错,所以就选择VisualVM来分析JVM性能 ...

  8. 八 SpringMVC文件上传,必须设置表单提交为post

    1 修改Tomcat配置,本地目录映射 那么在server.xml中体现为: 测试一下是否设置成功: 2 引入jia包   3 配置多媒体解析器 3 jsp开启图片上传 4 Controller层设置 ...

  9. MyBatis模糊查询异常: '%${}''读取jdbc属性

    '%${}''总是传root, 后来发现${username}读取了jdbc里面的属性username,于是将jdbc属性名修改,成功

  10. 2_03_MSSQL课程_查询_分组和连接

    “查” 的三种查询语句 where Group by  having  where 对表起作用 (原始硬盘上的表) 单纯的表 having 对结果起作用(筛选) 缓存,不在文件中 select --第 ...