一、内容
1、阻塞和非阻塞是什么?
2、传统IO模型,他存在哪些阻塞点
3、NIO模型
4、对比总结
1、阻塞和非阻塞是什么?
阻塞:做某件事情,直到完成,除非超时,如果没有完成,继续等待。
非阻塞:做一件事情,尝试着做,如果说不能做完,就不做了。意思就是直接返回,如果能做完,就做。
2、传统IO模型,他存在哪些阻塞点
1) 传统IO:Socket编程 参考:Android 网络编程 Socket
2) 阻塞点:
1> Socket socket = serverSocket.accept();
2> int data = is.read(b);
缺点:如下图的,
客户: socket
大门: ServerSocket(port)
服务器: Thread
每个服务员服务一个客户,高并发下会出现很多线程。

优点:
2) NIO
增加了一个重要的角色(Selector),主要负责调度和监控客户端和服务端(调度器)
由阻塞方式改成了非阻塞(non-blocking)
阻塞点
this.selector.select();
真正关系的阻塞点是: 读取数据
3、NIO例子
/**
* NIO Socket
*/
public class NioSocketDemo {
private Selector selector; //通道选择器(管理器)
public static void main(String[] args) throws IOException {
NioSocketDemo nio = new NioSocketDemo();
nio.initServer(8888);
nio.listenSelector();
}
public void initServer(int port) throws IOException{
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//设置非阻塞
serverSocketChannel.configureBlocking(false);
serverSocketChannel.socket().bind(new InetSocketAddress(port));
this.selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务已启动");
}
public void listenSelector() throws IOException{
//轮询监听selector
while (true) {
//等待客户连接
// select 模型,多路复用
this.selector.select();
Iterator<SelectionKey> iteKey = this.selector.selectedKeys().iterator();
while (iteKey.hasNext()) {
SelectionKey key = iteKey.next();
iteKey.remove();
//处理请求
handler(key);
}
}
}
/**
* 处理客户端请求
* @param key
* @throws IOException
*/
private void handler(SelectionKey key) throws IOException {
if(key.isAcceptable()){
//处理客户端连接请求事件
ServerSocketChannel serverSocketChannel = (ServerSocketChannel)key.channel();
SocketChannel socketChannel = serverSocketChannel.accept();
//设置非阻塞
socketChannel.configureBlocking(false);
//接收客户端发送的信息,需要给通道设置读的权限
socketChannel.register(selector, SelectionKey.OP_READ);
}else if (key.isReadable()){
//处理读的事件
SocketChannel socketChannel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int readData = socketChannel.read(buffer);
if(readData > 0){
String info = new String(buffer.array(), "GBK").trim();
System.out.println("服务端收到数据:" + info);
}else {
System.out.println("客户端关闭了...");
key.cancel();
}
}
}
}
启动Demo
![]()
启动客户端
打开CMD,
![]()
按住Ctrl + ] 进入

输入send hello world

发出send hello world后,服务端将收到数据: hello world
4、总结
传统IO