共计 1682 个字符,预计需要花费 5 分钟才能阅读完成。
java nio 提供了一套称为 I / O 多路复用的编程范式,那么什么叫做 I / O 多路复用呢?所谓的 I / O 多路复用,从字面意思上来理解,就是:有多个 I / O 操作 (或是写,或是读,或是请求),这多个 I / O 操作都共用一个逻辑流。为了讲清复用的是什么,首先得先说明一下逻辑流的概念。逻辑流是什么?这里的逻辑流和操作系统中 ” 线程是进程的一个逻辑流 ” 是一个意思。下面的就是一个逻辑流:
{
int a = 5;
int b a*a;
double c = a/b;
}
下面又是一个逻辑流:
{
long b = 5;
int c = b+3;
}
如果在一个进程中,如果没有线程,那么程序是顺序执行的,那么所有的代码都是属于一个逻辑流。比如说,上面的两端代码,如果合在一个进程当中,它们一定是这种结构:
{
int a = 5;
int b a*a;
double c = a/b;
}
….
{
long b = 5;
int c = b+3;
}
或是
{
long b = 5;
int c = b+3;
}
….
{
int a = 5;
int b a*a;
double c = a/b;
}
也就是说它们一定属于一个逻辑流 (一个顺序结构)。理解了这个,那么所谓的 I / O 复用,指的就是在一个逻辑流里处理多个 I / O 事件!!!如何做到?利用 Selector 多路复用器,轮询监听各路 I /O,如果一旦有 I / O 事件发生,那么就去处理,否则程序阻塞。来看一个程序, 加深理解:
package qiuqi.filedownloadtest;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;
public class FileServer {
public static void main(String[] args) throws IOException {
startServer();
}
public static void startServer() throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.bind(new InetSocketAddress(9999));
serverSocketChannel.configureBlocking(false);
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0)
{
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext())
{
SelectionKey key = iterator.next();
iterator.remove();
if(key.isAcceptable())
{
System.out.println(“ 收到连接这个 I / O 事件 ”);
catch (IOException e){e.printStackTrace();}
}
}
}
}
}
这是一个监听网络 I / O 的多路复用程序,java 中只能监听网络 I /O,不能监听标准输入输出等 I /O(不过这些在 linux 里都可以)。我们发现,这个程序的原理就是开启一个网络 I / O 类,ServerSocketChannel,把它注册到 Selector(选择器) 上,然后选择器就开始轮询,直到发现一个 I / O 事件,于是就进入第一个 while 循环进行处理,否则一直阻塞在 select()>0 处。这是一个极其简陋的程序,但是它揭示了多路复用的真正内涵,也就是用一个逻辑流监听,处理多个 I /O( 不过处理程序其实可以开启多线程,也就是指第一个 while 循环里的部分)。这就是 I / O 多路复用!!!