java支持3种网络编程模型I/O模式:BIO(同步并阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)
阻塞指的是访问IO的线程是否会阻塞(或等待)。线程访问资源,该资源是否准备就绪的一种处理方式。
阻塞与非阻塞:
同步与异步:
BIO:同步阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善。
代码示例:
public class ServerDemo { public static void main(String[] args) throws IOException { ServerSocket serverSocket=new ServerSocket(9999); ExecutorService executorService = Executors.newCachedThreadPool(); while (true){ Socket socket=serverSocket.accept(); System.out.println("有客户端连接"); executorService.execute(new Runnable() { @Override public void run() { InputStream inputStream = null; try { inputStream = socket.getInputStream(); byte[] b=new byte[1024]; int read = inputStream.read(b); System.out.println("收到客户端信息:"+new String(b,0,read)); OutputStream outputStream = socket.getOutputStream(); outputStream.write("你好客户端".getBytes(Charset.defaultCharset())); } catch (IOException e) { e.printStackTrace(); } } }); } } } public class ClientDemo { public static void main(String[] args) throws IOException { Socket socket=new Socket("127.0.0.1",9999); OutputStream outputStream = socket.getOutputStream(); outputStream.write("你好服务端".getBytes(Charset.defaultCharset())); InputStream inputStream = socket.getInputStream(); byte[] bytes=new byte[1024]; inputStream.read(bytes); System.out.println("收到服务端消息:"+new String(bytes)); socket.close(); } }BIO问题分析:
每个请求都需要创建独立的线程,与对应的客户端进行数据Read、业务处理、数据Write
并发数较大时,需要创建大量线程来处理连接,系统资源占用较大
连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在Read操作上,造成资源阻塞。
1.2 NIONIO:同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求就进行处理。
代码示例:
public class NioSelectorServer { public static void main(String[] args) throws IOException, InterruptedException { //1.打开服务器通道 ServerSocketChannel serverSocketChannel=ServerSocketChannel.open(); //2.绑定端口号 serverSocketChannel.bind(new InetSocketAddress(9999)); //3.设置通道为非阻塞 serverSocketChannel.configureBlocking(false); //4.创建选择器 Selector selector = Selector.open(); //5.将服务端通道注册到选择器上,并指定注册监听事件为OP_ACCEPT serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT); while (true){ //6.检查选择器释放有事件 // int select = selector.select(2000); int select = selector.select(); if(select==0){ System.out.println("无连接"); continue; } //7.获取事件集合 Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); while (iterator.hasNext()){ SelectionKey selectionKey = iterator.next(); //8.判断事件是否是连接事件 if(selectionKey.isAcceptable()){ //9.得到客户端通道,并将通道注册到选择器上 SocketChannel socketChannel = serverSocketChannel.accept(); System.out.println("有客户端连接"); socketChannel.configureBlocking(false); socketChannel.register(selector,SelectionKey.OP_READ); } //10.判断是否是读就绪事件 else if(selectionKey.isReadable()){ SocketChannel channel = (SocketChannel)selectionKey.channel(); ByteBuffer byteBuffer=ByteBuffer.allocate(1024); //11.得到客户端通道,读取数据到缓冲区 int read = 0; read = channel.read(byteBuffer); System.out.println("客户端消息:"+new String(byteBuffer.array())); System.out.println("模拟业务处理中。。。"); Thread.sleep(5000); if(read>0){ //12.回写数据给客户端 channel.write(ByteBuffer.wrap("你好客户端".getBytes(StandardCharsets.UTF_8))); channel.close(); } } //13.从集合删除对应事件,防止二次处理 iterator.remove(); } } } } 1.3 AIO