
课程咨询: 400-996-5531 / 投诉建议: 400-111-8989
认真做教育 专心促就业
高并发编程开发是目前大多数软件开发项目都需要满足的一个编程开发需求,而本文我们就通过案例分析来简单了解一下,java程序员如何优化I/O操作。
面对以上两个性能问题,不仅编程语言对此做了优化,各个操作系统也进一步优化了I/O。JDK1.4发布了java.nio包(newI/O的缩写),NIO的发布优化了内存复制以及阻塞导致的严重性能问题。JDK1.7又发布了NIO2,提出了从操作系统层面实现的异步I/O。下面我们就来了解下具体的优化实现。
1.使用缓冲区优化读写流操作
传统I/O提供了基于流的实现,即InputStream和OutputStream,这种基于流的实现以字节为单位处理数据。
与传统I/O不同,NIO是基于块(Block)的,以块为基本单位处理数据。在NIO中,重要的两个组件是缓冲区(Buffer)和通道(Channel)。Buffer是一块连续的内存区域,作为NIO读写数据的中转站。Channel表示数据缓冲的源头或目的地,用于读取缓冲或写入数据,是访问缓冲的接口。
传统I/O和NIO之间的大区别在于:传统I/O面向流,而NIO面向Buffer。Buffer允许将文件一次性读入内存后再进行后续处理,而传统方式是边读文件边处理数据。尽管传统I/O也使用了缓冲块,如BufferedInputStream,但其性能仍无法与NIO相提并论。使用NIO替代传统I/O操作可以显著提升系统的整体性能。
2.使用DirectBuffer减少内存复制
NIO的Buffer除了做了缓冲块优化之外,还提供了一个可以直接访问物理内存的类DirectBuffer。普通的Buffer分配的是JVM堆内存,而DirectBuffer是直接分配物理内存(非堆内存)。
我们知道数据要输出到外部设备,必须先从用户空间复制到内核空间,再复制到输出设备,而在Java中,在用户空间中又存在一个拷贝,那就是从Java堆内存中拷贝到临时的直接内存中,通过临时的直接内存拷贝到内存空间中去。此时的直接内存和堆内存都是属于用户空间。
3.避免阻塞,优化I/O操作
NIO很多人也称之为Non-blockI/O,即非阻塞I/O,因为这样叫,更能体现它的特点。为什么这么说呢?
传统的I/O即使使用了缓冲块,依然存在阻塞问题。由于线程池线程数量有限,一旦发生大量并发请求,超过大数量的线程就只能等待,直到线程池中有空闲的线程可以被复用。而对Socket的输入流进行读取时,读取流会一直阻塞,直到发生以下三种情况的任意一种才会解除阻塞:
有数据可读;
连接释放;
空指针或I/O异常。
阻塞问题,就是传统I/O大的弊端。NIO发布后,通道和多路复用器这两个基本组件实现了NIO的非阻塞,下面我们就一起来了解下这两个组件的优化原理。
通道(Channel)
前面我们讨论过,传统I/O的数据读取和写入是从用户空间到内核空间来回复制,而内核空间的数据是通过操作系统层面的I/O接口从磁盘读取或写入。
开始,在应用程序调用操作系统I/O接口时,是由CPU完成分配,这种方式大的问题是“发生大量I/O请求时,非常消耗CPU“;之后,操作系统引入了DMA(直接存储器存储),内核空间与磁盘之间的存取完全由DMA负责,但这种方式依然需要向CPU申请权限,且需要借助DMA总线来完成数据的复制操作,如果DMA总线过多,就会造成总线冲突。
通道的出现解决了以上问题,Channel有自己的处理器,可以完成内核空间和磁盘之间的I/O操作。在NIO中,我们读取和写入数据都要通过Channel,由于Channel是双向的,所以读、写可以同时进行。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!请读者仅作参考。更多内容请加抖音太原达内IT培训学习了解。