在介绍非阻塞IO存在的问题之前,先来写一个阻塞IO通信的demo。
服务器端代码:
@Slf4j
public class Demo1Server {
public static void main(String[] args) throws IOException {
// 创建服务器Socket,监听指定端口
ServerSocket serverSocket = new ServerSocket(8888);
log.info("Server started. Waiting for client connection...");
// 等待客户端连接
Socket socket = serverSocket.accept();
log.info("Client connected.");
// 获取输入流和输出流
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
// 读取客户端发送的数据
byte[] buffer = new byte[1024];
int bytesRead = inputStream.read(buffer);
String requestData = new String(buffer, 0, bytesRead);
log.info("Received data from client: " + requestData);
// 向客户端发送响应数据
String responseData = "Hello from server!";
outputStream.write(responseData.getBytes());
outputStream.flush();
log.info("Response sent to client.");
// 关闭连接
socket.close();
serverSocket.close();
}
}
客户端代码:
@Slf4j
public class Demo1Client {
public static void main(String[] args) throws IOException {
// 创建客户端Socket,指定服务器地址和端口
Socket socket = new Socket("localhost", 8888);
// 获取输入流和输出流
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
// 向服务器发送数据
String requestData = "Hello from client!";
outputStream.write(requestData.getBytes());
outputStream.flush();
log.info("Request sent to server.");
// 读取服务器响应数据
byte[] buffer = new byte[1024];
int bytesRead = inputStream.read(buffer);
String responseData = new String(buffer, 0, bytesRead);
log.info("Received response from server: " + responseData);
// 关闭连接
socket.close();
}
}
上述代码演示的是客户端与服务器端的一次通信,如果服务端要不断的接收不同客户端的请求,那么服务端的代码需要修改为循环accept,并且需要使用多线程的方式,不然服务端只能处理完一个请求再去处理下一个请求。
如果我们将代码编写为以多线程的方式处理请求,每次来一个新的请求都创建一个线程去处理,这样会导致一个问题:内存资源迟早耗尽。有没有办法可以解决这个问题呢?有的,那就是线程池。
不过引入线程池只是解决了内存耗尽的问题,但这里还存在一个问题:如果一个线程在处理请求的过程中由于其他的IO事件或计算事件导致阻塞,那么该线程也无法处理其他请求,这样的话,就没有充分利用系统资源。而一旦大量的线程碰到这种阻塞,那么系统的整体性能也会受到很大的影响。
为了解决上述问题,NIO就应运而生了。