资讯专栏INFORMATION COLUMN

17.13 非阻塞 I/O

Luosunce / 296人阅读

摘要:异步模式处理请求时,提供支持和的。服务方法首先通过调用请求对象的方法将请求置于异步模式,这是使用非阻塞所必需的。

应用程序的web容器通常为每一个客户端请求分配一个服务端线程。开发可扩展的web应用,你必须确保关联请求的线程是没有空闲的,不需要等待一个阻塞操作完成。异步处理提供了在一个新线程处理阻塞操作的机制,把关联请求的线程返回给容器。即使你所有的阻塞操作都在service方法中异步执行,关联客户端请求的线程基于input/output也可能出于暂时空闲状态。
例如,如果一个客户端在一个很慢的网络连接上提交一个大的HTTP POST请求,server读取请求的速度比客户端上传的速度快很多。使用TIO,容器关联请求的线程有时会出于空闲状态,因为要等待客户端的请求的其余部分。
JAVA EE异步模式处理请求时,提供支持servlet和filter的NIO。下面的步骤总结了在service方法中如何使用NIO处理请求和写出响应:

1. 如 Asynchronous Processing章节描述,把请求设置为异步模式  
2. 在service方法中从请求和响应对象中获得一个请求流或一个响应流
3. 分配给请求流一个监听器或者分配给响应流一个监听器 
4. 在监听器的回调方法中处理请求和响应
NIO 支持类 javax.servlet.ServletInputStream

方法签名:void setReadListener(ReadListener rl)
描述:将输入流与包含回调方法的监听器对象关联,以异步读取数据。提供的监听器对象可以是一个匿名类或者使用其他的机制给监听器对象传入输入流。
方法签名:boolean isReady()
方法描述:如果数据可以无阻塞读取,返回true
方法签名:boolean isFinished()
方法描述:当所有数据读取完毕后,返回true

NIO 支持类 javax.servlet.ServletOutputStream

方法签名:void setWriteListener(WriteListener wl)
方法描述:将此输出流与包含回调方法的侦听器对象关联,以异步写入数据。
您将写入侦听器对象提供为匿名类,或使用其他机制将输出流传递给写入侦听器对象。
方法签名:boolean isReady()
方法描述:如果数据可以无阻塞写入,返回true

NIO监听器支持接口

接口名称:ReadListener
接口方法:void onDataAvailable()、void onAllDataRead()、void onError(Throwable t)
描述:ServletInputStream当数据可以有效读取、当数据读取完毕、当发生一个错误时调用监听器的这些方法。
接口名称:WriteListener
接口方法:void onWritePossible()、void onError(Throwable t)
描述:ServletOutputStream当数据可以无阻塞读取、当发生一个错误时调用监听器的这些方法。

使用NIO读取大的HTTP POST请求

本节代码展示了在servlet对象中怎么读取一个大的HTTP POST数据,通过把请求放入异步模式中并使用NIO功能。

@WebServlet(urlPatterns={"/asyncioservlet"}, asyncSupported=true)
public class AsyncIOServlet extends HttpServlet {
   @Override
   public void doPost(HttpServletRequest request, 
                      HttpServletResponse response)
                      throws IOException {
      final AsyncContext acontext = request.startAsync();
      final ServletInputStream input = request.getInputStream();
      
      input.setReadListener(new ReadListener() {
         byte buffer[] = new byte[4*1024];
         StringBuilder sbuilder = new StringBuilder();
         @Override
         public void onDataAvailable() {
            try {
               do {
                  int length = input.read(buffer);
                  sbuilder.append(new String(buffer, 0, length));
               } while(input.isReady());
            } catch (IOException ex) { ... }
         }
         @Override
         public void onAllDataRead() {
            try {
               acontext.getResponse().getWriter()
                                     .write("...the response...");
            } catch (IOException ex) { ... }
            acontext.complete();
         }
         @Override
         public void onError(Throwable t) { ... }
      });
   }
}

此示例使用@WebServlet批注参数asyncSupported = true声明具有异步支持的Web Servlet。服务方法首先通过调用请求对象的startAsync()方法将请求置于异步模式,这是使用非阻塞I / O所必需的。然后,服务方法获得与请求相关联的输入流,并分配定义为内部类的读取侦听器。侦听器在可用时读取部分请求,然后在完成读取请求时将一些响应写入客户端。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74325.html

相关文章

  • Nodejs高性能原理(上) --- 异步阻塞事件驱动模型

    摘要:使用了一个事件驱动非阻塞式的模型,使其轻量又高效。的包管理器,是全球最大的开源库生态系统。按照这个定义,之前所述的阻塞,非阻塞,多路复用信号驱动都属于同步。 系列文章 Nodejs高性能原理(上) --- 异步非阻塞事件驱动模型Nodejs高性能原理(下) --- 事件循环详解 前言 终于开始我nodejs的博客生涯了,先从基本的原理讲起.以前写过一篇浏览器执行机制的文章,和nodej...

    yy736044583 评论0 收藏0
  • 物联网高并发编程之网络编程中的I/O模型

    摘要:缺点每个连接需要独立的进程线程单独处理,当并发请求量大时为了维护程序,内存线程切换开销较大,这种模型在实际生产中很少使用。而在系统下,才引入,目前并不完善,因此在下实现高并发网络编程时都是以复用模型模式为主。 思维导图 showImg(https://segmentfault.com/img/bVbkrNz?w=1766&h=994); 互联网服务端处理网络请求的原理 首先看看一个典型...

    hsluoyz 评论0 收藏0
  • nginx、swoole高并发原理初探

    摘要:一阅前热身为了更加形象的说明同步异步阻塞非阻塞,我们以小明去买奶茶为例。等奶茶做好了,店员喊一声小明,奶茶好了,然后小明去取奶茶。将响应结果发给相应的连接请求处理完成因为基于,所以每个可以处理无数个连接请求。如此,就轻松的处理了高并发。 一、阅前热身 为了更加形象的说明同步异步、阻塞非阻塞,我们以小明去买奶茶为例。 1、同步与异步 ①同步与异步的理解 同步与异步的重点在消息通知的方式上...

    denson 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<