首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > Web前端 >

您还在用IO吗

2012-11-23 
你还在用IO吗?回顾传统有必要了解传统的I/O操作的方式。以网络应用为例,传统方式需要监听一个ServerSocket,

你还在用IO吗?

回顾传统
有必要了解传统的I/O操作的方式。以网络应用为例,传统方式需要监听一个ServerSocket,接受请求的连接为其提供服务(服务通常包括了处理请求并发送响应),下图是服务器的生命周期图,其中标有粗黑线条的部分表明会发生I/O阻塞。

?

您还在用IO吗

?

? 线程使得服务器可以处理多个连接,但是它们也同样引发了许多问题。每个线程拥有自己的栈空间并且占用一些CPU时间,耗费很大,而且很多时间是浪费在阻塞的I/O操作上,没有有效的利用CPU。


? 选择NIO

? NIO包(java.nio.*)引入了四个关键的抽象数据类型,它们共同解决传统的I/O类中的一些问题。
1. Buffer:它是包含数据且用于读写的线形表结构。其中还提供了一个特殊类用于内存映射文件的I/O操作。
2. Charset:它提供Unicode字符串影射到字节序列以及逆影射的操作。
3. Channels:包含socket,file和pipe三种管道,它实际上是双向交流的通道,你可能注意到现有的java.io类中没有一个能够读写Buffer类型,所以NIO中提供了Channel类来读写Buffer。channel就是一个读写的管道,通过管道的读写来完成IO操作。channel分为ServerSocketChannel和SocketChannel,前者用于监听,获得客户端的连接,后者直接用于操作IO,来看看Channel如何进行Socket操作
4. Selector:它将多元异步I/O操作集中到一个或多个线程中,在过去的阻塞I/O中,我们一般知道什么时候可以向stream中读或写,因为方法调用直到stream准备好时返回。但是使用非阻塞通道,我们需要一些方法来知道什么时候通道准备好了。在NIO包中,设计Selector就是为了这个目的。SelectableChannel可以注册特定的事件,而不是在事件发生时通知应用,通道跟踪事件。然后,当应用调用Selector上的任意一个selection方法时,它查看注册了的通道看是否有任何感兴趣的事件发生

?

String host = 127.0.0.1;InetSocketAddress socketAddress = new InetSocketAddress(host, 80);ServerSocketChannel  ssc = ServerSocketChannel.open();//配置channel的阻塞模式ssc.configureBlocking(false);ssc.connect(socketAddress);Selector selector = Selector.open(); //将ServerSocketChannel注册到selector上,selector可以检测多路channelssc.register(selctor, SelectionKey.OP_ACCEPT);while(true){    //阻塞等待事件响应    selector.select();    Set<SelectionKey> selectionKeys = selector.selectedKeys();    Iterator<SelectionKey> it = selectionKeys.iterator();    //获得多路的channel,这些channel此时都已准备就绪,工作在非阻塞模式,可以非阻塞读写    while (it.hasNext()) {             SelectionKey key = it.next();             it.remove();             if (key.isAcceptable()) {             ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();         //此时的accept是非阻塞的,立马返回            SocketChannel channel = serverSocketChannel.accept();             channel.configureBlocking(false);         //可以不断得将这些channel注册成不同的类型,使之即可读,又可写            channel.register(selector, SelectionKey.OP_READ);             } else if (key.isReadable()) {             SocketChannel channel = (SocketChannel) key.channel();        //非阻塞读,立马返回数据        channel.read(buffer);        //...        SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_WRITE);             selectionKey.attach(new HandleClient(clientName));              } else if (key.isWritable()) {             SocketChannel channel = (SocketChannel) key.channel();             HandleClient handleClient = (HandleClient) key.attachment();             ByteBuffer buffer = handleClient.readBlock();                    }         } }

?

在这种模式下,原来负责端口监听的accept()方法换成了select()方法,两者都是阻塞的,本质上没有分别.区别在于select()之后返回的所有channel都是非阻塞的,都是可以马上读写的。而accept()之后的channel则是阻塞的,不能保证此时返回的channel的读写能够马上返回。因此,NIO的非阻塞方式就可以设置比较少的线程,因为这些线程拿到的channel都是立马可以读写的,这些线程的工作都是满负荷的,效率高。反之,阻塞方式需要创建同样较多的线程,因为这些线程很多都处于阻塞休眠状态,大家都不是满负荷在工作。这样NIO的优点就很明显了。

热点排行