彻底转变流,第2部分:优化Java内部I/O - 编程入门网
的性能问题:
对于不同的使用情况,大小为 1024 字节的内部缓冲区并不都适用;对于大 容量的数据,该缓冲区太小了。 基于数组的操作只是反复调用低效的一个字节一个字节地复制操作。该操作 本身是同步的,从而导致非常严重的锁争用。 如果管道变空或变满而在这种状态改变时一个线程阻塞了,那么,即使仅有 一个字节被读或写,该线程也被唤醒。在许多情况下,线程将使用这一个字节并 立即再次阻塞,这将导致只做了很少有用的工作。 最后一个因素是 API 提供的严格的约定的后果。对于最通用的可能的应用程 序中使用的流来说,这种严格的约定是必要的。但是,对于管道流实现,提供一 种更宽松的约定是可能的,这个约定牺牲严格性以换取性能的提高: 仅当缓冲区的可用数据(对阻塞的读程序而言)或可用空间(对写程序而言 )达到指定的某个 滞后阈值或发生异常事件(例如管道关闭)时,阻塞的读程 序和写程序才被唤醒。这将提高性能,因为仅当线程能完成适度的工作量时它们 才被唤醒。 只有一个线程可以从管道读取数据,只有一个线程可以把数据写到管道。否 则,管道无法可靠地确定读程序线程或写程序线程何时意外死亡。 这个约定可完全适合典型应用程序情形中独立的读程序线程和写程序线程; 需要立即唤醒的应用程序可以使用零滞后级别。我们将在后面看到,这个约定的 实现的操作速度比标准 API 流的速度快两个数量级(100 倍)。 我们可以使用几个可能的 API 中的一个来开发这些管道流:我们可以模仿标 准类,显式地连接两个流;我们也可以开发一个 Pipe 类并从这个类抽取输出流 和输入流。我们不使用这两种方式而是使用更简单的方式:创建一个 PipeInputStream ,然后抽取关联的输出流。 彻底转变流,第2部分:优化Java内部I/O(6)时间:2011-06-21 Merlin Hughes这些流的一般操作如下: 我们把内部数组用作环缓冲区(请看图 1):这个数组中维护着一个读索引 和一个写索引;数据被写到写索引所指的位置,数据从读索引所指的位置被读取 ;当两个索引到达缓冲区末尾时,它们回绕到缓冲区起始点。任一个索引不能超 越另一个索引。当写索引到达读索引时,管道是满的,不能再写任何数据。当读 索引到达写索引时,管道是空的,不能再读任何数据。 同步被用来确保两个协作线程看到管道状态的最新值。Java 语言规范对内存 访问的顺序的规定是很宽容的,因此,无法使用无锁缓冲技术。 图 1. 环缓冲区 在下面的代码清单中给出的是实现这些管道流的代码。清单 8 显示了这个类 所用的构造函数和变量。您可以从这个 InputStream 中抽取相应的 OutputStream (请看清单 17 中的代码)。在构造函数中您可以指定内部缓冲 区的大小和滞后级别;这是缓冲区容量的一部分,在相应的读程序线程或写程序 线程被立即唤醒前必须被使用或可用。我们维护两个变量, reader 和 writer ,它们与读程序线程和写程序线程相对应。我们用它们来发现什么时候一个线程 已死亡而另一个线程仍在访问流。 清单 8. 一个替代的管道流实现
|
凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢! |