BIO:同步阻塞IO(平常说的IO指的是BIO)
NIO:同步非阻塞IO
AIO:异步非阻塞IO
io操作分为两部分,发起io请求,和io数据读写。
阻塞、非阻塞主要是针对线程发起io请求后,是否立即返回来定义的,立即返回称为非阻塞io,否则称为阻塞io。
同步、异步主要针对io数据读写来定义的,读写数据过程中不阻塞线程称为异步io,否则,称为同步io。
一、BIO
线程发起io请求后,一直阻塞(阻塞io),直到数据就绪后,用户线程将数据写入socket空间,或从socket空间读取数据(同步)。
JDK5之前, JDK的IO模式只有BIO(同步阻塞)。
问题:因为阻塞的存在, 需对每个请求开启一个线程. 过多的线程切换影响操作系统性能。
解决:使用线程池, 处理不过来的放入队列, 再处理不过来的会触发其他机制。
问题::超过线程池数量的请求需要等待。
1. 客户端

public class Client { final static String ADDRESS = "127.0.0.1"; final static int PORT = 8765; public static void main(String[] args) throws IOException { Socket socket = null; BufferedReader in = null; PrintWriter out = null; try { socket = new Socket(ADDRESS, PORT); in = new BufferedReader(new InputStreamReader(socket.getInputStream())); out = new PrintWriter(socket.getOutputStream(), true); // true自动flush //向服务器端发送数据 out.println("来自客户端的请求"); //从服务端接收数据 String response = in.readLine(); // 阻塞 System.out.println("Client获取数据: " + response); } catch (Exception e) { e.printStackTrace(); } finally { out.close(); in.close(); socket.close(); } } }
2. 服务端
(1) 一个请求~一个线程

public class Server { final static int PROT = 8765; public static void main(String[] args) throws IOException { ServerSocket server = null; try { server = new ServerSocket(PROT); System.out.println("server start"); while(true){ Socket socket = server.accept(); //监听 阻塞 , socket底层会新建线程处理与客户端的三次握手 //建立线程处理获取的 socket new Thread(new ServerHandler(socket)).start(); } } catch (Exception e) { e.printStackTrace(); } finally { server.close(); } } } class ServerHandler implements Runnable { private Socket socket; public ServerHandler(Socket socket) { this.socket = socket; } @Override public void run() { BufferedReader in = null; PrintWriter out = null; try { in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); out = new PrintWriter(this.socket.getOutputStream(), true); String body = null; while (true) { body = in.readLine(); // 阻塞 if (body == null) break; System.out.println("Server获取的请求: " + body); out.println("来自服务器的响应"); } } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); in.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
(2) 线程池处理

public class Server { final static int PORT = 8765; public static void main(String[] args) throws IOException { ServerSocket server = null; try { server = new ServerSocket(PORT); System.out.println("server start"); HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 1000); while(true){ Socket socket = server.accept(); executorPool.execute(new ServerHandler(socket)); } } catch (Exception e) { e.printStackTrace(); } finally { server.close(); } } } class HandlerExecutorPool { private ExecutorService executor; public HandlerExecutorPool(int maxPoolSize, int queueSize){ this.executor = new ThreadPoolExecutor( // 带阻塞队列的线程池 Runtime.getRuntime().availableProcessors(), // 初始线程数 maxPoolSize, // 线程数上限 如果要处理请求的Runnable对象装满了队列, 则提高现有线程数 120L, // 如在120个时间颗粒内某线程是空闲的, 将被回收 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueSize) // 存放处理请求的Runnable对象 ); } public void execute(Runnable task){ this.executor.execute(task); } } class ServerHandler implements Runnable { private Socket socket; public ServerHandler(Socket socket) { this.socket = socket; } @Override public void run() { BufferedReader in = null; PrintWriter out = null; try { in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); out = new PrintWriter(this.socket.getOutputStream(), true); String body = null; while (true) { body = in.readLine(); if (body == null) break; System.out.println("Server获取的请求: " + body); // 阻塞 out.println("来自服务器的响应"); } } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); in.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
二、IO多路复用(NIO)