java中IO和NIO的区别和适用场景

  这几天主要学习了 NIO ,因为之前对 IO 使用的也比较多,所以有一个简单的对比,并且把学习的成果记录下来。

 

java.NIO包里包括三个基本的组件

l buffer:因为NIO是基于缓冲的,所以buffer是最底层的必要类,这也是IONIO的根本不同,虽然stream等有buffer开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而NIO却是直接读到buffer中进行操作。

因为读取的都是字节,所以在操作文字时,要用charset类进行编解码操作。

l channel:类似于IOstream,但是不同的是除了FileChannel,其他的channel都能以非阻塞状态运行。FileChannel执行的是文件的操作,可以直接DMA操作内存而不依赖于CPU。其他比如socketchannel就可以在数据准备好时才进行调用。

l selector:用于分发请求到不同的channel,这样才能确保channel不处于阻塞状态就可以收发消息。

面向流与面向缓冲

Java NIOIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

 

补充一点:NIObuffer可以使用直接内存缓冲区,该缓冲区不在JVM中,性能会比JVM的缓冲区略好,不过会增加相应的垃圾回收的负担,因为JVM缓冲区的性能已经足够好,所以除非在对缓冲有特别要求的地方使用直接缓冲区,尽量使用JVM缓冲。

阻塞与非阻塞

Java IO是阻塞式的操作,当一个inputstreamoutputstream在进行read()或write()操作时,是一直处于等待状态的,直到有数据读/写入后才进行处理.NIO是非阻塞式的,当进行读写操作时,只会返回当前已经准备好的数据,没有就返回空,这样当前线程就可以处理其他的事情,提高了资源的使用率.

与传统IO的优势

在老的IO包中,serverSocketsocket都是阻塞式的,因此一旦有大规模的并发行为,而每一个访问都会开启一个新线程。这时会有大规模的线程上下文切换操作(因为都在等待,所以资源全都被已有的线程吃掉了),这时无论是等待的线程还是正在处理的线程,响应率都会下降,并且会影响新的线程。

 

NIO包中的serverSocketsocket就不是这样,只要注册到一个selector中,当有数据放入通道的时候,selector就会得知哪些channel就绪,这时就可以做响应的处理,这样服务端只有一个线程就可以处理大部分情况(当然有些持续性操作,比如上传下载一个大文件,用NIO的方式不会比IO好)。

 

 

通过两个图的比较,可以看出IO是直连的,每个请求都给一条线程来处理,但是NIO却是基于反应堆(selector)来处理,直到读写的数据准备好后,才会通知相应的线程来进行处理。一言以蔽之:“selector不会让channel白占资源,没事的时候给我去睡觉。”

PS:NIO基于字节进行传输,在IO时要注意decode/encode

 

这里贴出一个基于Tcp的通信操作,体现出了NIO在处理小字节片的优势,比如用一个服务端程序就可以处理所有的客户端请求:

 

TCPProtocol接口

/**

 * TCPServerSelector与特定协议间通信的接口

 *

 * @date    2010-2-3

 * @time    上午08:42:42

 * @version 1.00

 */

publicinterface TCPProtocol{

/**

   * 接收一个SocketChannel的处理

   * @param key

   * @throws IOException

   */

void handleAccept(SelectionKey keythrows IOException;

 

/**

   * 从一个SocketChannel读取信息的处理

   * @param key

   * @throws IOException

   */

void handleRead(SelectionKey keythrows IOException;

 

/**

   * 向一个SocketChannel写入信息的处理

   * @param key

   * @throws IOException

   */

void handleWrite(SelectionKey keythrows IOException;

}

 

TCPProtocol实现类

/**

 * TCPProtocol的实现类

 *

 * @date    2010-2-3

 * @time    上午08:58:59

 * @version 1.00

 */

publicclass TCPProtocolImpl implements TCPProtocol{

privateintbufferSize;

 

public TCPProtocolImpl(intbufferSize){

this.bufferSize=bufferSize;

  }

 

publicvoid handleAccept(SelectionKey keythrows IOException {

    SocketChannel clientChannel=((ServerSocketChannel)key.channel()).accept();

clientChannel.configureBlocking(false);

clientChannel.register(key.selector(),SelectionKey.OP_READ,ByteBuffer.allocate(bufferSize));

  }

 

publicvoid handleRead(SelectionKey keythrows IOException {

// 获得与客户端通信的信道

    SocketChannel clientChannel=(SocketChannel)key.channel();

 

// 得到并清空缓冲区

    ByteBuffer buffer=(ByteBuffer)key.attachment();

buffer.clear();

 

// 读取信息获得读取的字节数

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值