BIO(Blocking IO)多线程版本
BIO多线程版本即每次客户端来连接时,都单独创建一个线程和客户端进行通信。
代码示例
public static void main(String[] args) throws IOException {
ServerSocket socket = new ServerSocket(8082);
while (true) {
try{
System.out.println("服务器启动,等待连接, 第一次阻塞");
Socket clientSocket = socket.accept();
System.out.println("客户端连接成功: " + clientSocket);
new Thread(() -> {
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = clientSocket.getInputStream();
clientSocket.getOutputStream();
byte[] bytes = new byte[1024];
int length;
System.out.println("连接成功,准备读数据, 第二次阻塞");
while ((length = inputStream.read(bytes)) != -1) {
System.out.println(length);
String clientMsg = new String(bytes, 0, length - 2);
System.out.println(clientMsg);
if ("over".equals(clientMsg)) {
break;
}
}
outputStream = clientSocket.getOutputStream();
outputStream.write("hello world".getBytes("utf-8"));
outputStream.flush();
System.out.println("数据读取成功,继续等待下一个客户端连接");
} catch (IOException e) {
e.printStackTrace();
}
}).start();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭input流代码省略
}
}
}
操作流程
服务端启动后端,创建三个客户端通过telnet与服务端进行通信,客户端分别发送hello,hello2,hello3,服务端日志如下
服务器启动,等待连接, 第一次阻塞
客户端连接成功: Socket[addr=/0:0:0:0:0:0:0:1,port=63515,localport=8082]
服务器启动,等待连接, 第一次阻塞
连接成功,准备读数据, 第二次阻塞
7
hello
客户端连接成功: Socket[addr=/0:0:0:0:0:0:0:1,port=63546,localport=8082]
服务器启动,等待连接, 第一次阻塞
连接成功,准备读数据, 第二次阻塞
8
hello2
客户端连接成功: Socket[addr=/0:0:0:0:0:0:0:1,port=63576,localport=8082]
服务器启动,等待连接, 第一次阻塞
连接成功,准备读数据, 第二次阻塞
8
hello3
结论
多线程版本的BIO,解决了单线程版本BIO的不能同时和多个客户端通信的问题,可以看见,很有效果。不过就是每次和服务端建立连接之后,都是新创建一个线程,这样的成本也有点高,所以有部分人就觉得BIO多线程版本也是一无是处,简直不能容忍。但是我想说的是,随着时代的变化,硬件水平的提升,我们的电脑再也不是单核,双核,而是4核,8核,16核,我们的内存容量也越来越大,多年以前,创建一个线程的成本或许真的很高,但是今时不同往日,现在创建线程的成本已经大大降级,有结果证明,经典多线程版本的性能,比NIO要高30%。当然也不是说NIO不好,就是想说,BIO多线程模型,也并不是一无是处。