HTML5技术

java十分钟速懂知识点——NIO - oO脾气不坏Oo

字号+ 作者:H5之家 来源:博客园 2015-11-29 15:41 我要评论( )

一、引子 nio是java的IO框架里边十分重要的一部分内容,其最核心的就是提供了非阻塞IO的处理方式,最典型的应用场景就是处理网络连接。很多同学提起nio都能说起一二,但是细究其背后的原理、思想往往就开始背书,说来说去都是那么几句,其中不少人并不见的真

一、引子

    nio是java的IO框架里边十分重要的一部分内容,其最核心的就是提供了非阻塞IO的处理方式,最典型的应用场景就是处理网络连接。很多同学提起nio都能说起一二,但是细究其背后的原理、思想往往就开始背书,说来说去都是那么几句,其中不少人并不见的真的很理解。本人之前就属于此类,看了很多书和博客,但是大多数都只是讲了三件套和怎么使用,很少会很细致的讲背后的思想,那本次我们就来扒一扒吧。
    很多博客描述nio都是这么说的:基于Reactor模式实现的多路非阻塞高性能的网络IO。那么我们就从这个定义来分析,其中两个关键点:多路非阻塞和Reactor模式。(本来想把高性能也算进去,但是后来想想这个应该算前两者的结果)下边我们来分别搞懂这两块。

二、网络IO模型

  • 阻塞IO:java中老的bio便是这种模式,在接到事件(数据到达、数据拷贝完成等)前程序需阻塞等待。优点是编码简单,缺点是效率低,处理程序阻塞会导致cpu利用率很低。
  • 非阻塞IO:在未接到事件时处理程序一直主动轮询,这样处理程序无需阻塞,可以在轮询间歇去干别的,但是轮询会造成重复请求,同样浪费资源。以前java中实现的的伪异步模式就是采用这种思想。
  • IO复用模型:增加了对socket的事件监听器(selector),从而把处理程序和对应的socket事件解耦,所用的socket连接都注册在监听器,在等待阶段只有监听器会阻塞,处理线程从监听器获取事件对socket连接处理即可,而且一个处理线程可以对应多个连接(前两种一般都是一个socket连接起一个线程,这就是为什么叫复用),有点是节省资源,由于处理程序能够被多个连接复用,因此少数的线程就能处理大量连接。缺点同样因为复用,如果是大量费时处理的连接(如大量连接上传大文件),很容易造成线程占满而导致新连接失败。
  • 信号驱动IO模型:在数据准别阶段无需阻塞,只需向系统注册一个信号,在数据准备好后,系统会响应该信号。该模型依赖于系统实现,而且信号通信使用比较麻烦,因此java中未有对应实现。
  • 异步IO:与信号驱动IO很类似,而且在数据拷贝阶段(指数据从系统缓冲区拷贝至程序自己的缓冲区,其他模型改阶段程序都需要阻塞等待)同样可以异步处理。有点不必多说,效率很高,缺点是依赖系统底层实现。目前很多语言都提供该模型的实现,jdk1.7之后同样在concurrent包中提供了。

  • 四、NIO

        NIO的细节就不多讲了,这里只介绍下三件套:

  • channel:管道,可以看做对流的封装,有点像pipe,不过其是全双工的。其好处是屏蔽了底层细节,不用关心流对应的是文件还是网络,也不用关心连接怎么处理的,而且全双工,不用考虑输入流或输出流,你只用使用buffer对其进行读写就行了。
  • buffer:channel的好基友,底层就是个字节数组,不同的是对其进行了封装,不仅提供了对基本类型的支持,而且内部维持了读写位置(postion、limit、capacity、mark等),还提供了便捷的方法(clear、flip)。对channel的读写必须通过buffer。
  • selector:这个不多说了,如果前边认真看基本上就明白干啥的,就是Reactor模式中Acceptor的实现。
  •     再来看个简图吧:


    五、一个例子

        从《netty权威指南》上抄了个例子以及配图,而且代码没有客户端的,大家可以瞄一眼吧(为什么没有?因为已经快一点了,我不想写了......):
    服务器端时序图:

    客户端时序图:

    服务器端代码:

    package com.gj.netty.nio; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.util.Iterator; import java.util.Set; /** * Created by guojing on 2015/6/7. MultiplexerTimerServer implements Runnable { private Selector selector; private ServerSocketChannel servChannel; stop; public MultiplexerTimerServer(int port) { try { selector = Selector.open(); //新建多路复用selector servChannel = ServerSocketChannel.open(); //新建channel servChannel.configureBlocking(false); //设置非阻塞 servChannel.socket().bind(new InetSocketAddress(port),1024); //端口、块大小 servChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("TimeServer is start, port:" + port); } catch (IOException e) { e.printStackTrace(); } } public void run() { while (!stop){ try { selector.select(1000); Set<SelectionKey> keys = selector.selectedKeys(); Iterator<SelectionKey> ketIt = keys.iterator(); SelectionKey key = null; while (ketIt.hasNext()){ key = ketIt.next(); ketIt.remove(); //处理对应key事件 handler(key); } } catch (IOException e) { e.printStackTrace(); } } } private void handler(SelectionKey key){ //根据key去除channel做对应处理 } }

    View Code

    六、最后一点啰嗦

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • Java 8 Lambda 表达式 - Felix_ICanFixIt

      Java 8 Lambda 表达式 - Felix_ICanFixIt

      2017-04-22 17:04

    • Omi v1.0.2发布 - 正式支持传递javascript表达式 - 【当耐特】

      Omi v1.0.2发布 - 正式支持传递javascript表达式 - 【当耐特】

      2017-03-22 11:03

    • JavaWeb与Asp.net工作原理比较分析 - 社会主义接班人

      JavaWeb与Asp.net工作原理比较分析 - 社会主义接班人

      2017-03-12 14:00

    • 一道面试题引发的对javascript类型转换的思考 - ChokCoco

      一道面试题引发的对javascript类型转换的思考 - ChokCoco

      2017-03-06 17:00

    网友点评