Java IO方式有很多种,传统的io包中,基于流模型,提供了一些熟知的File抽象,InputStream,OutputStream输入输出流,
输入流,输出流(InputStream,OutputStream)是用于读取或写入字节的,例如操作图片、文件,读写出来的是byte字节数组 Reader、Writer则是用于操作字符,适用于类似从文件中读取或者写入文本信息,读写的是字符,char,string BufferedOutputStream等缓冲区的实现,可以避免频繁的磁盘读写,进而提高IO效率,利用了缓冲区,将批量数据进行一次操作,需要flush。获得一个inputStream 将inputStream转换成InputStreamReader 使用BufferedReader装饰 InputStreamReader 来读取具体内容 (1)字符与字节: FileInputStream 类以二进制输入/输出,I/O速度快且效率高,但是它的read()方法读到的是一个字节(二进制数据),很不利于人们阅读,而且无法直接对文件中的字符进行操作,比如替换,查找(必须以字节形式操作); 而Reader类弥补了这个缺陷,可以以文本格式输入/输出,非常方便;比如可以使用while((ch = filereader.read())!=-1 )循环来读取文件;可以使用BufferedReader的readLine()方法一行一行的读取文本。
Java IO是面向流的,每次从流(InputStream/OutputStream)中读一个或多个字节,直到读取完所有字节,它们没有被缓存在任何地方。另外,它不能前后移动流中的数据,如需前后移动处理,需要先将其缓存至一个缓冲区。 Java NIO面向缓冲,数据会被读取到一个缓冲区,需要时可以在缓冲区中前后移动处理,这增加了处理过程的灵活性。但与此同时在处理缓冲区前需要检查该缓冲区中是否包含有所需要处理的数据,并需要确保更多数据读入缓冲区时,不会覆盖缓冲区内尚未处理的数据。
当然java.net包下的网络编程API如ServerSocket,Socket也属于IO行为。
BIO:Blocking I/O,同步阻塞IO,在读写操作时,系统是阻塞的,如果是单线程同时只有一个连接能执行,线性顺序,只能通过开启多线程方式来提高CPU利用率,因此设计了每连接每线程模型,开启多线程,充分使用CPU资源。现在多线程一般都使用线程池,减少线程创建与销毁的成本。 局限性: 1.线程的创建和销毁成本很高,像Java线程栈,每个线程一般至少分配512K-1M的空间。 2.线程的切换成本很高,由于需要保留线程上下文,如果线程数过高,线程切换的时间甚至大于线程执行时间。 3.容易造成锯齿状的系统负载,一旦线程数量高且外部网络不稳定,很容易出现大量请求的结果阻塞后同时返回,造成系统崩溃。
NIO:非阻塞IO,引入SocketServerChannel,SocketChannel,Selector选择器等,同时NIO提供的FileChannel:transferTo和transferFrom可直接把数据从一个Channel拷贝到另一个Channel,广泛用于高效的网络文件传输和大文件拷贝。 使用select或epoll实现IO多路复用,解决了BIO中一个线程只能管理一个连接的缺陷。 其中select的Reactor模式更是提高了CPU的利用率。Netty就是使用多Reactor模式。 Reactor模式:




使用NIO != 高性能,当连接数<1000,并发程度不高或者局域网环境下NIO并没有显著的性能优势。 推荐大家使用成熟的NIO框架,如Netty,MINA等。解决了很多NIO的陷阱,并屏蔽了操作系统的差异,有较好的性能和编程模型。 AIO:异步非阻塞IO TODO
Buffer的选择 如我们发送微信消息:由于用户态权限的限制,需要先将消息从用户态拷贝到内核态,再由内核态往网卡写入。服务器端的内核态操作网卡,把数据从网卡拷贝到内核态,再由内核态拷贝到用户态。 通常情况下,操作系统的一次写操作分为两步: 1. 将数据从用户态拷贝到内核态。 2. 从内核态往网卡写。同理,读操作也分为两步: ① 将数据从网卡拷贝到系统空间; ② 将数据从系统空间拷贝到用户空间。 对于NIO来说,缓存的使用可以使用DirectByteBuffer和HeapByteBuffer。如果使用了DirectByteBuffer,一般来说可以减少一次系统空间到用户空间的拷贝。但Buffer创建和销毁的成本更高,更不宜维护,通常会用内存池来提高性能。 如果数据量比较小的中小应用情况下,可以考虑使用heapBuffer;反之可以用directBuffer。 使用NIO != 高性能,当连接数<1000,并发程度不高或者局域网环境下NIO并没有显著的性能优势。 NIO并没有完全屏蔽平台差异,它仍然是基于各个操作系统的I/O系统实现的,差异仍然存在。使用NIO做网络编程构建事件驱动模型并不容易,陷阱重重。 推荐大家使用成熟的NIO框架,如Netty,MINA等。解决了很多NIO的陷阱,并屏蔽了操作系统的差异,有较好的性能和编程模型。 最后总结一下到底NIO给我们带来了些什么: 事件驱动模型 避免多线程 单线程处理多任务 非阻塞I/O,I/O读写不再阻塞,而是返回0 基于block的传输,通常比基于流的传输更高效 更高级的IO函数,zero-copy IO多路复用大大提高了Java网络应用的可伸缩性和实用性 tech.meituan.com/2016/11/04/…