- 浏览: 70356 次
- 性别:
- 来自: 武汉
最新评论
-
wanglantao:
谢谢了!!!!
ext中文API文档及例子 -
lilongsy:
问一下,phpcms和supesite哪个更好用?
我现在用 ...
phpcms转supesite转换程序bug修正 -
hwn0412:
辛苦了..刚好要用..
Ajax框架之ExtJs、DWR入门书籍 -
wkl17:
感谢楼主分享,但是step4修改了之后,进行转换,会提示
引用 ...
phpcms转supesite转换程序bug修正 -
Chen_ZX:
之前接触得比较少,现在有时间多学习一点。谢谢分享!
ext中文API文档及例子
在JDK 1.4的新特性中,NIO无疑是最显著和鼓舞人心的。NIO的出现事实上意味着Java虚拟机的性能比以前的版本有了较大的飞跃。在以前的JVM的版本中,代码的执行效率不高(在最原始的版本中Java是解释执行的语言),用Java编写的应用程序通常所消耗的主要资源就是CPU,也就是说应用系统的瓶颈是CPU的计算和运行能力。在不断更新的Java虚拟机版本中,通过动态编译技术使得Java代码执行的效率得到大幅度提高,几乎和操作系统的本地语言(例如C/C++)的程序不相上下。在这种情况下,应用系统的性能瓶颈就从CPU转移到IO操作了。尤其是服务器端的应用,大量的网络IO和磁盘IO的操作,使得IO数据等待的延迟成为影响性能的主要因素。NIO的出现使得Java应用程序能够更加紧密地结合操作系统,更加充分地利用操作系统的高级特性,获得高性能的IO操作。
一、 NIO基本概念
NIO在磁盘IO处理和文件处理上有很多新的特性来提高性能,本文不作详细的解释,而仅仅介绍NIO在处理网络IO方面的新特点,这些特点是理解Grizzly的最基本的概念。
1. 数据缓冲(Buffer)处理
数据缓冲(Buffer)是IO操作的基本元素。其实从本质上来说,无论是磁盘IO还是网络IO,应用程序所作的所有事情就是把数据放到相应的数据缓冲当中去(写操作),或者从相应的数据缓冲中提取数据(读操作)。至于数据缓冲中的数据和IO设备之间的交互,则是操作系统和硬件驱动程序所关心的事情了。因此,数据缓冲在IO操作中具有重要的作用,是操作系统与应用之间的IO桥梁。在NIO的包中,Buffer类是所有类的基础。 Buffer类当中定义数据缓冲的基本操作,包括put、get、reset、clear、flip、rewind等,这些基本操作是进行数据输入输出的手段。每一个基本的Java类型(boolean除外)都有相应的Buffer类,例如CharBuffer、IntBuffer、 DoubleBuffer、ShortBuffer、LongBuffer、FloatBuffer和ByteBuffer。我们所关心的是 ByteBuffer,因为操作系统与应用程序之间的数据通信最原始的类型就是Byte
数据缓冲的另外一个重要的特点是可以在一个数据缓冲上再建立一个或多个视图(View)缓冲。这个概念有些类似于数据库视图的概念:在数据库的物理表 (Table)结构之上可以建立多个视图。同样,在一个数据缓冲之上也可以建立多个逻辑的视图缓冲。视图缓冲的用处很多,例如可以将Byte类型的缓冲当作Int类型的视图,来进行类型转换。视图缓冲也可以将一个大的缓冲看成是很多小的缓冲视图。这对提高性能很有帮助,因为创建物理的数据缓冲(特别是直接的数据缓冲)是非常耗时的操作,而创建视图却非常快。在Grizzly中就有这方面的考虑。
2. 异步通道(Channel)
Channel(后文又称频道,译法仅暗示存在多通道可选)是NIO的另外一个比较重要的新特点。Channel并不是对原有Java类的扩充和完善,而是完全崭新的实现。通过Channel,Java应用程序能够更好地与操作系统的IO服务结合起来,充分地利用上文提到的ByteBuffer,完成高性能的IO操作。Channel的实现也不是纯Java的,而是和操作系统结合紧密的本地代码。
Channel的一个重要的特点是在网络套接字频道(SocketChannel)中,可以将其设置为异步非阻塞的方式。
非阻塞方式的频道使用:
通过SocketChannel.configureBlocking(false)就可以将网络套接字频道设置为异步非阻塞模式。一旦设置成非阻塞的方式,从Socket中读和写就再也不会阻塞。虽然非阻塞只是一个设置问题,但是对应用程序的结构和性能却产生了天翻地覆的变化。
3. 有条件的选择(Readiness Selection)
熟悉UNIX的程序员对POSIX的select()或poll()函数应该比较熟悉。在现在大多数流行的操作系统中,都支持有条件地选择已经准备好的IO通道,这就使得只需要一个线程就能同时有效地管理多个IO通道。在JDK 1.4以前,Java语言是不具备这个功能的。
NIO通过几个关键的类来实现这种有条件的选择的功能:
(1) Selector
Selector类维护了多个注册的Channel以及它们的状态。Channel需要向Selector注册,Selector负责维护和更新Channel的状态,以表明哪些Channel是准备好的。
(2) SelectableChannel
SelectableChannel是可以被Selector所管理的Channel。FileChannel不属于Selectable- Channel,而SocketChannel是属于这类的Channel。因此在NIO中,只有网络的IO操作才有可能被有条件地选择。
(3) SelectionKey
SelectionKey用于维护Selector和SelectableChannel之间的映射关系。当一个Channel向Selector注册之后,就会返回一个SelectionKey作为注册的凭证。SelectionKey中保存了两类状态值,一是这个Channel中哪些操作是被注册了的,二是有哪些操作是已经准备好的
二、 使用NIO来提高系统扩展性
NIO使用非阻塞的API,通过实现少量的线程就能服务于大量的并发用户的请求。并且通过操作系统都支持的POSIX标准的select方式,来获得系统准备就绪的资源。使用这些手段,NIO就能够充分利用每个活动的线程来服务于大量的请求,减少系统资源的浪费。通常来说,一个NIO的服务架构会采用以下的结构。
使用NIO的server编程框架:
上面的结构比起阻塞式的框架都复杂一些。具体说明如下:
通过ServerSocketChannel.open()获得一个Server的Channel对象。
通过Selector.open()来获得一个Selector对象。
从Server的Channel对象上可以获得一个Server的Socket,并让它在80端口监听。
通过ServerSocketChannel.configureBlocking(false)可以将当前的Channel配置成异步非阻塞的方式。如果没有这一步,那么Channel默认的方式跟传统的一样,是阻塞式的。
将当前的Channel注册到Selector对象中去,并告诉Selector当前的Channel关心的操作是OP_ACCEPT,也就是当有新的请求的时候,Selector负责更新此Channel的状态。
在循环当中调用selector.select(),如果当前没有任何新的请求过来,并且原来的连接也没有新的请求数据到达,这个方法会阻塞住,一直等到新的请求数据过来为止。
如果当前都请求的数据到达,那么selector.select()就会立刻退出,这时候可以从selector.selectedKeys()获得所有在当前selector注册过的并且有数据到达的这些Channel的信息(SelectionKey)。
遍历所有的这些SelectionKey来获得相关的信息。如果某个SelectionKey的操作是OP_ACCEPT,也就是isAcceptable,那么可以判定这是那个Server Channel,并且是有新的连接请求到达了。
当有新的请求来的时候,通过accept()方法可以获得新的channel服务于这个新来的请求。然后通过configureBlocking(false)可以将当前的Channel配置成异步非阻塞的方式。
接着将这个新的channel也注册到selector中,并告诉Selector当前的Channel关心的操作是OP_READ,也就是当前Channel有新的数据到达的时候,Selector负责更新此Channel的状态。
如果在循环当中发现某个SelectionKey的操作是OP_READ,也就是isReadable,那么可以判定这不是那个Server Channel,而是在循环内部注册的连接Channel,表明当前SelectionKey对应的这个Channel有数据到达了。
有数据到达之后的处理方式是下面要详细讨论的问题,在这里,我们简单地用一个方法readDataFromSocket(key)来表示,功能就是从这个Channel中读取数据。
从这个框架结构中可以看到,在一个线程中可以同时服务于多个连接,包括Server的监听服务。在同一个时刻,并不是所有的连接都会有数据到达,因此为每一个连接分配单独的线程没有必要。使用异步非阻塞方式,可以使用很少的线程,通过Select的方式来服务于多个连接请求,效率大大提高。
一、 NIO基本概念
NIO在磁盘IO处理和文件处理上有很多新的特性来提高性能,本文不作详细的解释,而仅仅介绍NIO在处理网络IO方面的新特点,这些特点是理解Grizzly的最基本的概念。
1. 数据缓冲(Buffer)处理
数据缓冲(Buffer)是IO操作的基本元素。其实从本质上来说,无论是磁盘IO还是网络IO,应用程序所作的所有事情就是把数据放到相应的数据缓冲当中去(写操作),或者从相应的数据缓冲中提取数据(读操作)。至于数据缓冲中的数据和IO设备之间的交互,则是操作系统和硬件驱动程序所关心的事情了。因此,数据缓冲在IO操作中具有重要的作用,是操作系统与应用之间的IO桥梁。在NIO的包中,Buffer类是所有类的基础。 Buffer类当中定义数据缓冲的基本操作,包括put、get、reset、clear、flip、rewind等,这些基本操作是进行数据输入输出的手段。每一个基本的Java类型(boolean除外)都有相应的Buffer类,例如CharBuffer、IntBuffer、 DoubleBuffer、ShortBuffer、LongBuffer、FloatBuffer和ByteBuffer。我们所关心的是 ByteBuffer,因为操作系统与应用程序之间的数据通信最原始的类型就是Byte
数据缓冲的另外一个重要的特点是可以在一个数据缓冲上再建立一个或多个视图(View)缓冲。这个概念有些类似于数据库视图的概念:在数据库的物理表 (Table)结构之上可以建立多个视图。同样,在一个数据缓冲之上也可以建立多个逻辑的视图缓冲。视图缓冲的用处很多,例如可以将Byte类型的缓冲当作Int类型的视图,来进行类型转换。视图缓冲也可以将一个大的缓冲看成是很多小的缓冲视图。这对提高性能很有帮助,因为创建物理的数据缓冲(特别是直接的数据缓冲)是非常耗时的操作,而创建视图却非常快。在Grizzly中就有这方面的考虑。
2. 异步通道(Channel)
Channel(后文又称频道,译法仅暗示存在多通道可选)是NIO的另外一个比较重要的新特点。Channel并不是对原有Java类的扩充和完善,而是完全崭新的实现。通过Channel,Java应用程序能够更好地与操作系统的IO服务结合起来,充分地利用上文提到的ByteBuffer,完成高性能的IO操作。Channel的实现也不是纯Java的,而是和操作系统结合紧密的本地代码。
Channel的一个重要的特点是在网络套接字频道(SocketChannel)中,可以将其设置为异步非阻塞的方式。
非阻塞方式的频道使用:
SocketChannel sc = SocketChannel.open(); sc.configureBlocking(false); // nonblocking ... if (!sc.isBlocking()) { doSomething(cs); }
通过SocketChannel.configureBlocking(false)就可以将网络套接字频道设置为异步非阻塞模式。一旦设置成非阻塞的方式,从Socket中读和写就再也不会阻塞。虽然非阻塞只是一个设置问题,但是对应用程序的结构和性能却产生了天翻地覆的变化。
3. 有条件的选择(Readiness Selection)
熟悉UNIX的程序员对POSIX的select()或poll()函数应该比较熟悉。在现在大多数流行的操作系统中,都支持有条件地选择已经准备好的IO通道,这就使得只需要一个线程就能同时有效地管理多个IO通道。在JDK 1.4以前,Java语言是不具备这个功能的。
NIO通过几个关键的类来实现这种有条件的选择的功能:
(1) Selector
Selector类维护了多个注册的Channel以及它们的状态。Channel需要向Selector注册,Selector负责维护和更新Channel的状态,以表明哪些Channel是准备好的。
(2) SelectableChannel
SelectableChannel是可以被Selector所管理的Channel。FileChannel不属于Selectable- Channel,而SocketChannel是属于这类的Channel。因此在NIO中,只有网络的IO操作才有可能被有条件地选择。
(3) SelectionKey
SelectionKey用于维护Selector和SelectableChannel之间的映射关系。当一个Channel向Selector注册之后,就会返回一个SelectionKey作为注册的凭证。SelectionKey中保存了两类状态值,一是这个Channel中哪些操作是被注册了的,二是有哪些操作是已经准备好的
二、 使用NIO来提高系统扩展性
NIO使用非阻塞的API,通过实现少量的线程就能服务于大量的并发用户的请求。并且通过操作系统都支持的POSIX标准的select方式,来获得系统准备就绪的资源。使用这些手段,NIO就能够充分利用每个活动的线程来服务于大量的请求,减少系统资源的浪费。通常来说,一个NIO的服务架构会采用以下的结构。
使用NIO的server编程框架:
public class Server { public static void main(String[] argv) throws Exception { ServerSocketChannel serverCh = ServerSocketChannel.open(); Selector selector = Selector.open(); ServerSocket serverSocket = serverCh.socket(); serverSocket.bind(new InetSocketAddress(80)); serverCh.configureBlocking(false); serverCh.register(selector,SelectionKey.OP_ACCEPT); while(true){ selector.select(); Iterator it = selector.selectedKeys().iterator(); while (it.hasNext()) { SelectionKey key = (SelectionKey)it.next(); if (key.isAcceptable()) { ServerSocketChannel server =(ServerSocketChannel)key.channel(); SocketChannel channel = server.accept(); channel.configureBlocking(false); channel.register(selector,SelectionKey.OP_READ); } if (key.isReadable()) { readDataFromSocket(key); } it.remove(); } } } }
上面的结构比起阻塞式的框架都复杂一些。具体说明如下:
通过ServerSocketChannel.open()获得一个Server的Channel对象。
通过Selector.open()来获得一个Selector对象。
从Server的Channel对象上可以获得一个Server的Socket,并让它在80端口监听。
通过ServerSocketChannel.configureBlocking(false)可以将当前的Channel配置成异步非阻塞的方式。如果没有这一步,那么Channel默认的方式跟传统的一样,是阻塞式的。
将当前的Channel注册到Selector对象中去,并告诉Selector当前的Channel关心的操作是OP_ACCEPT,也就是当有新的请求的时候,Selector负责更新此Channel的状态。
在循环当中调用selector.select(),如果当前没有任何新的请求过来,并且原来的连接也没有新的请求数据到达,这个方法会阻塞住,一直等到新的请求数据过来为止。
如果当前都请求的数据到达,那么selector.select()就会立刻退出,这时候可以从selector.selectedKeys()获得所有在当前selector注册过的并且有数据到达的这些Channel的信息(SelectionKey)。
遍历所有的这些SelectionKey来获得相关的信息。如果某个SelectionKey的操作是OP_ACCEPT,也就是isAcceptable,那么可以判定这是那个Server Channel,并且是有新的连接请求到达了。
当有新的请求来的时候,通过accept()方法可以获得新的channel服务于这个新来的请求。然后通过configureBlocking(false)可以将当前的Channel配置成异步非阻塞的方式。
接着将这个新的channel也注册到selector中,并告诉Selector当前的Channel关心的操作是OP_READ,也就是当前Channel有新的数据到达的时候,Selector负责更新此Channel的状态。
如果在循环当中发现某个SelectionKey的操作是OP_READ,也就是isReadable,那么可以判定这不是那个Server Channel,而是在循环内部注册的连接Channel,表明当前SelectionKey对应的这个Channel有数据到达了。
有数据到达之后的处理方式是下面要详细讨论的问题,在这里,我们简单地用一个方法readDataFromSocket(key)来表示,功能就是从这个Channel中读取数据。
从这个框架结构中可以看到,在一个线程中可以同时服务于多个连接,包括Server的监听服务。在同一个时刻,并不是所有的连接都会有数据到达,因此为每一个连接分配单独的线程没有必要。使用异步非阻塞方式,可以使用很少的线程,通过Select的方式来服务于多个连接请求,效率大大提高。
评论
2 楼
maysnow1979
2009-06-02
学习了, 不太懂.呵呵
1 楼
bachmozart
2009-04-06
个人觉得Java的IO服用模型封装的实在不怎么样,很多地方不好理解,本来操作系统简单的API和编程模型都是比较好理解的,被Java封装一层后反而很难看清楚类之间的关系
发表评论
-
supesite系统视频播放功能的分析及设置默认打开页面播放
2009-12-16 20:34 1924最近做的一个php项目需求中有视频这个频道,于是研究了一下su ... -
php之smarty技术中文文档
2009-12-07 19:46 1229最近因工作关系投身于了php语言.基于上都是基于supesit ... -
phpcms转supesite转换程序bug修正
2009-12-03 21:13 1999因客户前期使用的门户站是phpcms产品,现要升级到康盛的su ... -
Android通用布局对象
2009-09-02 14:49 3162FrameLayout FrameLayout is the ... -
java p2p技术
2009-07-27 10:45 5196英文原文地址: http://ww ... -
承接Java项目
2009-07-13 15:09 1011本人从事软件开发4年,主要为供电局做远程集抄、营销系统、MIS ... -
WEB前端高性能优化之JavaScript优化细节
2009-06-11 14:07 804作为一名网站开发WEB前端工程师,对自己开发的网站项目应该尽可 ... -
Ext官方中文教程
2009-03-25 15:09 3723Extjs.com官方中文教程列表: so good~~! ... -
程序员的十层楼(菜鸟,大虾,牛人......)
2009-03-19 10:41 1125到底中国的程序员水平比西方程序员水平差,还是中国有许多优秀的程 ... -
欲为Java技术大牛所需的25个学习要点
2009-02-24 10:17 7931. 你需要精通面向对象 ... -
Java对象的生命周期分析
2009-01-17 15:20 2510从以下可心看出使 ... -
软件工程师不可不知的10个概念
2009-01-17 13:27 711出色的软件工程师善用设计模式,勤于代码重构,编写单元测试,并对 ... -
类设计的技巧
2008-12-31 10:09 932设计一个类要明确这个类所要完成的功能,类里的成员变量和 ... -
架构设计的几个心得
2008-12-24 09:57 882一,不要过设计:never o ... -
B/S前端优化
2008-12-03 12:02 8691. 合并脚本文件 包括 ... -
30个优秀源码网站
2008-11-28 14:25 1187从csdn上摘录下来,记录一下 1.51源码:http:// ... -
避免发生与安全有关的javascript错误
2008-11-28 11:40 985會產生 JavaScript錯誤: eval() 函數 s ... -
java socket/Serversocket编程详解(中/英文)
2008-10-23 15:09 2456socket /套接字 Sockets let y ... -
ext中文API文档及例子
2008-09-26 18:51 5347附件为一个chm文件,主要以ext文档为主,还附有一些ext包 ... -
Eclipse匆删恢复
2008-09-20 16:05 1318昨天coding时,不知道是脑袋抽筋还是咋滴了,一不小心把一个 ...
相关推荐
首先,理解NIO(Non-blocking Input/Output)的概念至关重要。NIO与传统的IO模型不同,它提供了对多路复用器的支持,如Java的Selector类,可以同时监控多个通道的状态变化,从而提高了系统在高并发环境下的性能。在...
首先,让我们了解NIO的基本概念。传统的Java IO基于流和字节缓冲区,采用阻塞I/O模型,即当一个操作(如读或写)进行时,线程会阻塞直到该操作完成。而NIO引入了选择器(Selector)和通道(Channel)的概念,允许一...
`TestConnector.java`和`SocketTest.java`可能包含了此类客户端的示例代码,展示如何创建和管理Socket连接,以及发送和接收数据的基本流程。 相比之下,Mina NIO是一种基于Java NIO API的网络通信框架,它利用了多...
学习NIO,首先应了解其基本概念,然后通过实践操作通道、缓冲区和选择器,最后可以尝试将NIO应用于实际项目,例如构建一个简单的服务器,以巩固和提升技能。 总结来说,本资料包为学习NIO提供了一个良好的起点,...
这个简单的例子展示了如何使用Java NIO实现服务器和客户端的基本通信流程,但实际应用中可能还需要处理异常、数据解析、心跳检测等复杂逻辑。理解NIO的核心概念和API,对于构建高效、可扩展的网络应用至关重要。
1. **NIO基本概念** - **通道(Channels)**: 通道是NIO中的主要组件,它代表了I/O操作的对象,如文件、套接字等。通道可以读取或写入数据,并且可以是双向的。 - **缓冲区(Buffers)**: 缓冲区是数据在NIO系统中传输...
为了更好地理解Java NIO的使用方式,下面我们通过简单的代码示例来展示如何实现一个基本的NIO服务端和客户端。 **服务端代码实现** ```java package cn.nio; import java.io.IOException; import java.net....
首先,理解Java NIO的基本概念非常重要。NIO中的“N”代表“非阻塞”,这意味着在进行I/O操作时,程序可以继续执行其他任务,而不是等待数据传输完成。NIO的核心组件包括通道(Channels)、缓冲区(Buffers)和选择...
一、NIO的基本概念 1. 缓冲区(Buffer):NIO的核心组件,用于存储数据。Java提供了多种Buffer类,如ByteBuffer、CharBuffer、IntBuffer等,分别对应不同数据类型。每个Buffer都有特定的方法用于写入、读取、清理和...
从简单的缓冲区操作到复杂的异步I/O实现,每个示例都旨在帮助读者深入理解NIO的工作原理,并鼓励大家在自己的系统上编译和运行这些代码,亲身体验NIO带来的性能提升。 #### 结语 Java NIO作为现代Java开发中的关键...
1. **NIO的基本概念**:解释NIO的核心组件,如通道、缓冲区和选择器的工作原理。 2. **NIO的优势**:对比传统I/O,讨论NIO如何提高并发性能,特别是在处理大量连接的服务器场景下。 3. **服务器模型**:介绍基于NIO...
- **学习目标**:理解Socket通道的基本概念和使用场景。 #### 8. Java NIO-Channel-ServerSocketChannel - **主要内容**:详细介绍ServerSocketChannel的创建和使用方法。 - **学习目标**:学会如何创建并监听...
本文首先概述了NIO的基本组件,然后分析了非阻塞通信的工作机制,并通过一个具体的网络应用实例展示了如何实现非阻塞通信。 #### 引言 传统的Java I/O系统基于字节流和字符流的操作模式,存在处理速度较慢的问题。...
这个“socket简单示例JAVA源代码”很可能是展示如何创建、连接和通信的基本步骤。 首先,我们从`ServerSocket`开始。`ServerSocket`在服务器端创建,用于监听特定端口上的连接请求。例如: ```java ServerSocket ...
首先,了解 Java NIO 的基本概念是非常重要的。这包括理解缓冲区、通道、选择器等核心组件的工作原理以及它们之间的关系。 ##### 2. 编码实践 通过编写简单的示例代码来熟悉 NIO 的使用方法。可以从创建简单的缓冲...
NIO的核心概念是通道(Channel)和缓冲区(Buffer)。在NIO中,读写操作都是非阻塞的,即当数据没有准备好时,调用read或write方法不会被阻塞,而是立即返回。此外,NIO还引入了选择器(Selector),它能监控多个...
在深入探讨Java IO与Java NIO之间的区别之前,我们先简单回顾一下这两种I/O模型的基本概念。 #### 1. Java IO(Blocking IO) Java IO,也称为传统的阻塞式IO或同步阻塞式IO,是Java早期版本中的主要I/O处理方式。...
首先,我们需要理解NIO的基本概念。 NIO与传统的阻塞I/O(BIO)不同,它允许Java应用程序进行非阻塞的数据读写。在BIO中,每个连接都会创建一个单独的线程,当连接数量增加时,服务器可能会因为线程数量过多而资源...