Java NIO 入门介绍

Java NIO 入门介绍

阅读本文章时,需要你掌握以下知识点:
1. Java IO流的基本知识点,包括数据的写入读出等操作;
2. Java 多线程,并发编程的知识点,重点是多线程的理解;
3. Java Socket编程基础,可参看我的上篇关于Socket介绍的文章


1. 什么是Java NIO?

在介绍Java NIO之前,我想先介绍下为什么会出现Java NIO的概念。

在Socket编程中,数据传输是先创建Socket套接字再通过IO流进行数据的传输的。
当创建Socket对象时,双方的Socket实例都有一个Inputstream 和 Outputstream,操作系统会为Inputstream 和 Outputstream分配一定大小的缓存区,数据的读取与写入将在这个缓存区中进行;
写入端数据写入到Outputstream的SendQ队列当中,当队列信息满了的时候,数据又会转移到另一端Inputstream 的RecvQ队列中,如果RecvQ也满,那么Outputstream 的 write方法将会阻塞,直到RecvQ中有足够空间容纳SendQ发送的数据。
由于会发送阻塞,双方发送数据的时候容易产生死锁。

如何避免这种死锁情况呢?解决办法为在数据写入的时候能够同时进行读取操作。
NIO即提供了这种实现。


2. NIO

NIO,英文:New IO 或者是Non-Blocking IO,可翻译成新的IO或者是非阻塞式IO。

NIO与原来的IO有同样的作用,使用方式不一样。NIO支持面向缓冲区的、基于通道的IO操作,且以更高效的方式进行文件的读写操作(非阻塞式)。

Java NIO 由以下几个核心部分组成:
1. Channels
2. Buffers
3. Selectors

Java NIO系统的核心在于:通道(Channel) 和 缓冲区(Buffer) ,Channel负责传输,Buffer用于存储数据。

使用NIO时,首先通道(Channel) 打开到IO设备(如文件、套接字)的连接,然后操作缓冲区,对数据进行处理。

1) JAVA NIO中主要Channel的主要实现:
  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel
    上面四个刚好对应文件IO、UDP和TCP(Server和Client)

通道(Channel): 由java.io.channels包定义的。
Channel表示IO源与目标打开的连接。即你要想获取文件信息,需要先与Channel建立一个Channe。但是Channel不能直接访问数据,只能与Buffer进行交互。

2) Java NIO里关键的Buffer主要实现:
  • ByteBuffer
  • CharBuffer
  • DoubleBuffer
  • FloatBuffer
  • IntBuffer
  • LongBuffer
  • ShortBuffer
  • Mappedyteuffer
    这些Buffer覆盖了你能通过IO发送的基本数据类型:byte, short, int, long, float, double 和 char。

缓冲区(Buffer):由java.nio 包定义,用于特定基本数据类型的容器。说白了就是获取的不同类型的数据要放在对应类型的Buffer中。
Java NIO 中的Buffer主要用于与NIO通道进行交互,数据从通道读入缓冲区,从缓冲区写入通道。

上面两个概念可以由下图去理解:
这里写图片描述
即Channel提供从文件、网络读取数据的渠道,但是读写的数据都必须经过Buffer。

3) Java NIO里的Selector

Selector允许单线程处理多个 Channel。如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用Selector就会很方便。
这是在一个单线程中使用一个Selector处理3个Channel的图示;
这里写图片描述
要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件。


3.NIO 与 IO 的区别

传统IO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。
NIO 与 IO 的主要区别如下图所示:
这里写图片描述

1) 面向流与面向缓冲

Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。

  • Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。
    此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。

  • Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

2) 阻塞与非阻塞IO

Java IO的各种流是阻塞的。
当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再执行其他任务。
所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。

Java NIO是非阻塞模式。
当线程从某通道进行读写数据时,若没有数据可用时,该线程可以执行其他任务。所以单独的线程可以管理多个输入输出通道。因此,NIO可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。

3) 选择器(Selectors)

Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

Selector可以同时监控多个SelectableChannel 的 IO 的状况。利用Selector可使一个单独的线程管理多个Channel。Selector是非阻塞IO 的核心。

关于NIO的入门介绍今天就介绍到此,后续会陆续更新Buffer,Channel,Selector的具体操作以及编程实例。

本文参考资料:
http://www.iteye.com/magazines/132-Java-NIO
http://www.importnew.com/19816.html


第一次用Markdown写,有很多不习惯的地方,功能似乎也没有那么强大。但是简洁明了,妈妈再也不用担心写完的博客格式变了的问题了。

早点下班,做个按时吃喝的好程序员。
—————————————————————————— 2017/2/21 in ShangHai

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值