1.传统BIO线程模型/阻塞
1.1 单线程实现
来看下传统bio(单线程)的代码示例:
package com.hotpot.day01.bio;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 描述:传统Socket阻塞案例
* @author: myx
* @date: 2018/2/6 0006
* Copyright © 2017-ganinfo. All rights reserved.
*/
public class TraditionalSocketDemo{
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7777);
System.out.println("服务端启动...");
while(true){
// 获取socket套接字
// accept()阻塞点
Socket socket = serverSocket.accept();
System.out.println("有新客户端连接上来了...");
// 获取客户端输入流
InputStream is = socket.getInputStream();
byte[] b = new byte[1024];
while(true){
// 循环读取数据
// read() 阻塞点
int data = is.read(b);
if(data != -1){
String info = new String(b,0,data,"GBK");
System.out.println(info);
}else{
break;
}
}
}
}
}
采用一问一达的方式(一个服务端只能为一个客户端服务),就像是一个餐厅只能服务一个客人。
1.2 多线程实现
package com.hotpot.day01.bio;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 描述:传统bio多线程版本
* @author: myx
* @date: 2018/2/6 0006
* Copyright © 2017-ganinfo. All rights reserved.
*/
public class TraditionalSocketDemo2{
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(7777);
System.out.println("服务端启动...");
while(true){
// 获取socket套接字
// accept()阻塞点
Socket socket = serverSocket.accept();
System.out.println("有新客户端连接上来了...");
new Thread(new Runnable() {
@Override
public void run() {
try {
// 获取客户端输入流
InputStream is = socket.getInputStream();
byte[] b = new byte[1024];
while(true){
// 循环读取数据
// read() 阻塞点
int data = is.read(b);
if(data != -1){
String info = new String(b,0,data,"GBK");
System.out.println(info);
}else{
break;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}).start();
}
}
}
多线程结构图:
缺点:
当用户一直增长,对于服务的压力也是越来越大,会导致整个服务挂掉,就像是一个餐厅为了服务N个可能请了N个服务生,自然餐厅最后会黄调
1.3 线程池实现
package com.hotpot.day01.bio;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import static java.util.concurrent.Executors.newFixedThreadPool;
/**
* 描述:传统BIO 多线程伪异步IO
* @author: myx
* @date: 2018/2/6 0006
* Copyright © 2017-ganinfo. All rights reserved.
*/
public class TraditionalSocketMultiThreadDemo {
@SuppressWarnings("resource")
public static void main(String[] args) throws IOException {
// ExecutorService threadPool = Executors.newCachedThreadPool();// 线程池,缓存,无限大 m:m = 请求:线程 n:m n=>m=1
ExecutorService threadPool = newFixedThreadPool(100); // 请求:线程 = n:m (n>m)
ServerSocket serverSocket = new ServerSocket(7777);
System.out.println("服务端启动...");
while (true) {
// 获取socket套接字
// accept()阻塞点
Socket socket = serverSocket.accept();
threadPool.execute(new Runnable() {
@Override
public void run() {
try {
System.out.println("有新客户端连接上来了...");
// 获取客户端输入流
InputStream is = socket.getInputStream();
byte[] b = new byte[1024];
while (true) {
// 循环读取数据
// read() 阻塞点
int data = is.read(b);
if (data != -1) {
String info = new String(b, 0, data, "GBK");
System.out.println(info);
} else {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
});
}
}
}
缺点(伪异步IO):
当线程池已经用完所有线程,再来新的请求会等待,就像一个餐厅来了100个只有50个服务生,50人需要等待,会有客人不满意。
1.4 BIO问题总结
- 每当一个新的客户端请求接入时,服务端必须创建一个线程来处理这条链路
- 如果在高性能高并发场景下肯定是没法用的