知识大全 Java I/O API之性能分析 (上)

Posted

篇首语:登山则情满于山,观海则意溢于海。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 Java I/O API之性能分析 (上)相关的知识,希望对你有一定的参考价值。

Java I/O API之性能分析 (上)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  IO API的可伸缩性对Web应用有着极其重要的意义 Java 版以前的API中 阻塞I/O令许多人失望 从J SE 版本开始 Java终于有了可伸缩的I/O API 本文分析并计算了新旧I/O API在可伸缩性方面的差异      一 概述  IO API的可伸缩性对Web应用有着极其重要的意义 Java 版以前的API中 阻塞I/O令许多人失望 从J SE 版本开始 Java终于有了可伸缩的I/O API 本文分析并计算了新旧IO API在可伸缩性方面的差异 Java向Socket写入数据时必须调用关联的OutputStream的write()方法 只有当所有的数据全部写入时 write()方法调用才会返回 倘若发送缓冲区已满且连接速度很低 这个调用可能需要一段时间才能完成 如果程序只使用单一的线程 其他连接就必须等待 即使那些连接已经做好了调用write()的准备也一样 为了解决这个问题 你必须把每一个Socket和一个线程关联起来 采用这种方法之后 当一个线程由于I/O相关的任务被阻塞时 另一个线程仍旧能够运行     尽管线程的开销不如进程那么大 但是 考虑到底层的操作平台 线程和进程都属于消耗大量资源的程序结构 每一个线程都要占用一定数量的内存 而且除此之外 多个线程还意味着线程上下文的切换 而这种切换也需要昂贵的资源开销 因此 Java需要一个新的API来分离Socket与线程之间过于紧密的联系 在新的Java I/O API(java nio *)中 这个目标终于实现了     本文分析和比较了用新 旧两种I/O API编写的简单Web服务器 由于作为Web协议的HTTP不再象原来那样只用于一些简单的目的 因此这里介绍的例子只包含关键的功能 或者说 它们既不考虑安全因素 也不严格遵从协议规范      二 用旧API编写的HTTP服务器  首先我们来看看用旧式API编写的HTTP服务器 这个实现只使用了一个类 main()方法首先创建了一个绑定到 端口的ServerSocket     public static void main() throws IOException   ServerSocket serverSocket = new ServerSocket( );  for (int i= ; i < Integer parseInt(args[ ]); i++)   new Httpd(serverSocket);        接下来 main()方法创建了一系列的Httpd对象 并用共享的ServerSocket初始化它们 在Httpd的构造函数中 我们保证每一个实例都有一个有意义的名字 设置默认协议 然后通过调用其超类Thread的start()方法启动服务器 此举导致对run()方法的一次异步调用 而run()方法包含一个无限循环     在run()方法的无限循环中 ServerSocket的阻塞性accpet()方法被调用 当客户程序连接服务器的 端口 accept()方法将返回一个Socket对象 每一个Socket关联著一个InputStream和一个OutputStream 两者都要在后继的handleRequest()方法调用中用到 这个方法将读取客户程序的请求 经过检查和处理 然后把合适的应答发送给客户程序 如果客户程序的请求合法 通过sendFile()方法返回客户程序请求的文件 否则 客户程序将收到相应的错误信息(调用sendError())方法       while (true)      socket = serverSocket accept();     handleRequest();     socket close();      现在我们来分析一下这个实现 它能够出色地完成任务吗?答案基本上是肯定的 当然 请求分析过程还可以进一步优化 因为在性能方面StringTokenizer的声誉一直不佳 但这个程序至少已经关闭了TCP延迟(对于短暂的连接来说它很不合适) 同时为外发的文件设置了缓冲 而且更重要的是 所有的线程操作都相互独立 新的连接请求由哪一个线程处理由本机的(因而也是速度较快的)accept()方法决定 除了ServerSocket对象之外 各个线程之间不共享可能需要同步的任何其他资源 这个方案速度较快 但令人遗憾的是 它不具有很好的可伸缩性 其原因就在于 很显然地 线程是一种有限的资源      三 非阻塞的HTTP服务器  下面我们来看看另一个使用非阻塞的新I/O API的方案 新的方案要比原来的方案稍微复杂一点 而且它需要各个线程的协作 它包含下面四个类     NIOHttpd  Acceptor  Connection  ConnectionSelector    NIOHttpd的主要任务是启动服务器 就象前面的Httpd一样 一个服务器Socket被绑定到 端口 两者主要的区别在于 新版本的服务器使用java nio channels ServerSocketChannel而不是ServerSocket 在利用bind()方法显式地把Socket绑定到端口之前 必须先打开一个管道(Channel) 然后 main()方法实例化了一个ConnectionSelector和一个Acceptor 这样 每一个ConnectionSelector都可以用一个Acceptor注册 另外 实例化Acceptor时还提供了ServerSocketChannel     public static void main() throws IOException   ServerSocketChannel ssc = ServerSocketChannel open();  ssc socket() bind(new InetSocketAddress( ));  ConnectionSelector cs = new ConnectionSelector();  new Acceptor(ssc cs);      为了理解这两个线程之间的交互过程 首先我们来仔细地分析一下Acceptor Acceptor的主要任务是接受传入的连接请求 并通过ConnectionSelector注册它们 Acceptor的构造函数调用了超类的start()方法 run()方法包含了必需的无限循环 在这个循环中 一个阻塞性的accept()方法被调用 它最终将返回一个Socket对象——这个过程几乎与Httpd的处理过程一样 但这里使用的是ServerSocketChannel的accept()方法 而不是ServerSocket的accept()方法 最后 以调用accept()方法获得的socketChannel对象为参数创建一个Connection对象 并通过ConnectionSelector的queue()方法注册它     while (true)      socketChannel = serverSocketChannel accept();  connectionSelector queue(new Connection(socketChannel));         总而言之 Acceptor只能在一个无限循环中接受连接请求和通过ConnectionSelector注册连接 与Acceptor一样 ConnectionSelector也是一个线程 在构造函数中 它构造了一个队列 并用Selector open()方法打开了一个java nio channels Selector Selector是整个服务器中最重要的部分之一 它使得程序能够注册连接 能够获取已经允许读取和写入操作的连接的清单     构造函数调用start()方法之后 run()方法里面的无限循环开始执行 在这个循环中 程序调用了Selector的select()方法 这个方法一直阻塞 直到已经注册的连接之一做好了I/O操作的准备 或Selector的wakeup()方法被调用     while (true)      int i = selector select();  registerQueuedConnections();     // 处理连接       当ConnectionSelector线程执行select()时 没有一个Acceptor线程能够用该Selector注册连接 因为对应的方法是同步方法 理解这一点是很重要的 因此这里使用了队列 必要时Acceptor线程向队列加入连接     public void queue(Connection connection)   synchronized (queue)   queue add(connection);    selector wakeup();      紧接着把连接放入队列的操作 Acceptor调用Selector的wakeup()方法 这个调用导致ConnectionSelector线程继续执行 从正在被阻塞的select()调用返回 由于Selector不再被阻塞 ConnectionSelector现在能够从队列注册连接 在registerQueuedConnections()方法中 其实施过程如下     if (!queue isEmpty())   synchronized (queue)   while (!queue isEmpty())   Connection connection =  (Connection)queue remove(queue size() );  connection register(selector);       cha138/Article/program/Java/gj/201311/27392

相关参考

知识大全 分析 Java I/O 的工作机制

分析JavaI/O的工作机制  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  网络I/O优化  网

知识大全 高级图像处理图像I/O API RC 1.0

高级图像处理图像I/OAPIRC1.0  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  如果你对图

知识大全 Java I/O流

JavaI/O流  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  面向字节的流类  一预定义的流对

知识大全 Java I/O 包中的Decorator模式介绍

JavaI/O包中的Decorator模式介绍  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!JDK

知识大全 调整 JavaTM I/O 性能

调整JavaTMI/O性能  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  调整JavaTMI/O

知识大全 非阻塞I/O简介

Java网络编程从入门到精通(31):非阻塞I/O简介  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧

知识大全 一个非阻塞I/O的例子

Java网络编程从入门到精通(32):一个非阻塞I/O的例子  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看

知识大全 非阻塞I/O的缓冲区(Buffer)

Java网络编程从入门到精通(33):非阻塞I/O的缓冲区(Buffer)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我

知识大全 测量磁盘I/O

测量磁盘I/O  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!我怎样分离OracleI/O来使得性能

知识大全 java nio 开发实例

  首先了解下所谓的javanio是个什么东西!  传统的并发型服务器设计是利用阻塞型网络I/O以多线程的模式来实现的然而由  于系统常常在进行网络读写时处于阻塞状态会大大影响系统的性能自Java开始