Netty学习日记:传统阻塞IO与NIO的区别

1.传统阻塞I/O

ServerSocket serverSocket = new ServerSocket(portNumber); //监听指定端口的连接请求
Socket clientSocket = serverSocket.accept(); // accept()会一直阻塞直到获取连接,这个连接用于客户端和服务端之间的通信
BufferedReader in = new BufferedReader(
new InputStreamReader(clientSocket.getInputStream())); // 获取客户端socket输入流以读取客户端文本数据
PrintWriter out =
new PrintWriter(clientSocket.getOutputStream(), true); // 输出流将把服务端的响应发送给客户端
String request, response;
while ((request = in.readLine()) != null) { // readLine()将会阻塞直到有一个“换行符或回车符结尾”的字符串被读取
if ("Done".equals(request)) { //客户端发送"Done"则退出循环
break;
}
response = processRequest(request); // 处理客户端请求
out.println(response); //将服务端响应结果用输出流发送给客户端
}

这段代码只能同时处理一个客户端,所以要处理多个客户端并发时,需要为每个客户端Socket提供一个线程,如图所示:

这种方案有三个弊端:
1.这种情况下会产生大量的空闲线程,都在等待客户端输入数据,造成资源浪费;
2.我们知道虚拟机的方法栈是线程私有的,所以需要为每个线程的调用栈分配内存;
3.大数量线程上下文切换带来的开销。

2.Java NIO

NIO采用的是非阻塞方案,消除了上一节中所描述的弊端。而Java NIO是用Selector选择器来实现非阻塞I/O的。

它是用事件通知的方式来确定一组非阻塞Socket中有哪些已经就绪可以进行I/O操作,因为可以一直检查他们的读操作和写操作的完成状态,所以一个单一的线程就足以应对多个并发连接。
与传统阻塞I/O相比,这种方案提供了更好的资源管理:
1.用少量的线程就可以应对大量的连接,大大减少了内存管理和线程上下文切换带来的开销;
2.当没有I/O操作需要处理的时候,线程可以用来执行其他任务。

但是在高负载的情况下要可靠和高效地处理和调度I/O操作是一件繁琐且容易出错的任务,所以就有了后来的Netty,Netty就是基于NIO实现的。

posted @ 2020-11-04 18:13  Conwie  阅读(112)  评论(0编辑  收藏  举报