JDK中对IO的操作提供io
和nio
两个包,在这两个包中可以看到在io
包中,类名多以Stream结尾,而nio
包中多以Buffer
结尾。Java中NIO与IO的最大区别是IO面向流(Stream)的,NIO是面向缓冲(Buffer)。面向流意味着每次从流中读一个或多个字节,直至读取所有字节,读取的内容没有被缓存在任何地方,而且是顺序读取,它不能前后移动流中的数据,如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。NIO的缓冲导向方法略有不同,数据读取到一个可以稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据(譬如读入缓冲区中的数据不是一条完整的数据,需要与下一次读取的内容拼接),而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。
四种IO模型
同步和异步说的是消息的通知机制,阻塞非阻塞说的是线程的状态。一般来说 I/O 模型可以分为:同步阻塞、同步非阻塞、异步阻塞、异步非阻塞,四种IO模型:
参考链接:https://www.zhihu.com/question/27991975/answer/69041973 作者:郭无心
同步阻塞 IO
在此种方式下,用户进程在发起一个 IO 操作以后,必须等待 IO 操作的完成,只有当真正完成了 IO 操作以后,用户进程才能运行。Java传统的 IO 模型属于此种方式。
同步非阻塞 IO
在此种方式下,用户进程发起一个 IO 操作以后便可返回做其它事情,但是用户进程需要时不时的询问 IO 操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的 CPU 资源浪费。其中目前 Java 的 NIO 就属于同步非阻塞 IO。
异步阻塞 IO
此种方式下是指应用发起一个 IO 操作以后,不等待内核 IO 操作的完成,等内核完成 IO 操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问 IO 是否完成,那么为什么说是阻塞的呢?因为此时是通过 select 系统调用来完成的,而 select 函数本身的实现方式是阻塞的,而采用 select 函数有个好处就是它可以同时监听多个文件句柄,从而提高系统的并发性。
异步非阻塞 IO
在此种模式下,用户进程只需要发起一个 IO 操作然后立即返回,等 IO 操作真正的完成以后,应用程序会得到 IO 操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的 IO 读写操作,因为真正的 IO 读取或者写入操作已经由内核完成了。目前 Java 中还没有支持此种 IO 模型。
所有的Java IO流都是阻塞的,这意味着,当一条线程执行read()或者write()方法时,这条线程会一直阻塞知道读取到了一些数据或者要写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。而java NIO的非阻塞模式(Java NIO有阻塞模式和非阻塞模式,阻塞模式的NIO除了使用Buffer存储数据外和IO基本没有区别)允许一条线程从channel中读取数据,通过返回值来判断buffer中是否有数据,如果没有数据,NIO不会阻塞,因为不阻塞这条线程就可以去做其他的事情,过一段时间再回来判断一下有没有数据。NIO的写也是一样的,一条线程将buffer中的数据写入channel,它不会等待数据全部写完才会返回,而是调用完write()方法就会继续向下执行。
举例
io的读写
1 | /** |
nio的读写
1 | /** |