IO到NIO的一个转变
作者:互联网
本内容来源:Jack视频讲解和自己的一个理解。
1、故事还得从网络模型或者IO开始聊起
2、你有想过传统IO真正存在的问题吗?
3、如果你是设计者,IO可以怎样改进?
4、NIO原理分析以及代码实现
IO:不就是input和output吗。input:输入操作;output:输出操作;从jdk出生开始他就已经存在了,在jdk的java.io包下面。
我们都知道io是阻塞 io,那么想一下为什么是阻塞的?来看看下面这个IO的一个测试类
package com.test; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; /** * @Title: BIOServer * @Description: IO 测试 * @author: sunxuesong@hztianque.com * @date: Created in 20:05 2019/9/8 * @Modifired by: */ public class BIOServer { public static void main(String[] args) { try{ // socket监听,端口8888 ServerSocket serverSocket = new ServerSocket(8888); System.out.println("BIOServer has started,listening on port:" + serverSocket.getLocalSocketAddress()); // 不停的监听有没有客户端进行链接 while (true) { // 进行链接 Socket clientSocket = serverSocket.accept(); System.out.println("Connect from " + clientSocket.getRemoteSocketAddress()); try { // 客户端输入的内容 Scanner input = new Scanner(clientSocket.getInputStream()); // 这个while是用来客户端和服务器进行交互的,通过输出流进行数据写出 while (true) { String request = input.nextLine(); if ("quit".equals(request)) { break; } System.out.println(String.format("From %s : %s", clientSocket.getRemoteSocketAddress(), request)); String response = "From BIOServer Hello:" + request +".\n"; clientSocket.getOutputStream().write(response.getBytes()); } }catch (Exception e) { e.printStackTrace(); } } }catch (Exception e){ e.printStackTrace(); } } }
启动上面的main方法服务进行测试一下:
打开cmd 输入 telnet localhost 8888 回车,链接进来后,随便输入然后回车可以在控制台看到你输入的内容,这时候在来重新打开一个cmd,之前的cmd窗口不要关闭,这时候可以链接进来,但是这时候不管你怎么输入控制台都不会有反应,这是为什么呢?因为被阻塞了,在队列中进行等待,如果你关闭之前的cmd窗口,这时候控制台会立马看到你输入的内容。那既然这样就会有人说了我们可以使用多线程去操作,这种想法很好,在tomcat1.7之前tomcat也是这么做的,比如我用一个线程池大小是3,这时候最多支持3个客户端链接可以进行交互,如果第四个来了那么只能阻塞等待,因为前面的线程没有进行释放。
来看一下IO的模型:
1.阻塞io(Blocking I/O)
我来描述一下怎么请求的:首先用户去请求读取磁盘数据,这时候磁盘数据是受保护的不允许你直接去读取,它必须通过内核空间去读取(这是计算机自己的一个机制,分为用户空间和内核空间,用户空间就是我们的java进程,内核空间是计算机自己分配的),那么java是怎么做的呢?将请求交给内核空间,其他不用你去管。那么当java进程去内核空间拿数据的时候,这时候发现内核空间还没有将数据准备好,那他就会一直等待着,直到你准备好了为止。这时候等待的状态就是一个阻塞的状态,他不会释放cpu的资源。其他线程无法进行访问。
2:非阻塞IO(No Blocking I/O)
这个是怎么用的呢?我来解释一下他和上面的区别主要在于他不会去等待内核空间,当内核空间没有准备好数据的时候他直接返回了,不会占用资源。
3:复用IO
这种IO他不会一直等待,他有一个专门的线程来管理所有的客户端请求。他会一直轮询,知道发现有一个socket是read状态然后进行数据的一个读取。
这时候NIO就孕育而生了,他对上面的几个模型进行了一个取长补短的操作。
首先他用到了复用IO的selector机制,然后他发现内核空间进行复制磁盘数据的时候也是需要等待的,这时候他又引入了一个buffer的概念,buffer是一个可变的缓冲池,默认是1024个字节,当发现buffer中的缓冲池不够的时候会自动的扩容。基于这种高速的请求,那么客户端的链接速度肯定是跟不上的,于是nio有发明了channel的思想,多路复用的一个概念,相对io而言,他是双向的面向通道的,而io只是单向的面向流的。下节用源码说明一下nio的一个机制。
标签:java,NIO,IO,这时候,内核,io,转变,客户端 来源: https://www.cnblogs.com/sunxuesong/p/11499446.html