• NIO编程介绍


    I/O模型

    java支持3种网络编程模型I/O模式:BIO(同步并阻塞)、NIO(同步非阻塞)、AIO(异步非阻塞)

    阻塞指的是访问IO的线程是否会阻塞(或等待)。线程访问资源,该资源是否准备就绪的一种处理方式。

    阻塞与非阻塞:

    同步与异步:

    1.1 BIO

    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问题分析:

    1. 每个请求都需要创建独立的线程,与对应的客户端进行数据Read、业务处理、数据Write
    2. 并发数较大时,需要创建大量线程来处理连接,系统资源占用较大
    3. 连接建立后,如果当前线程暂时没有数据可读,则线程就阻塞在Read操作上,造成资源阻塞。

    1.2 NIO

    NIO:同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有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

    AIO引入了异步通道的概念,采用了Proactor模式,简化了程序编写。它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间比较长的应用。

    Proactor模式是一个消息异步通知的设计模式,Proactor通知的部署就绪事件,而是操作完成事件。

    适用场景

    1. BIO适用于连接数比较小且固定的架构,这种方式对服务器资源要求比较高
    2. NIO适用于连接数目多且比较短的架构,比如聊天服务器,弹幕系统,服务期间通讯等
    3. AIO适用于连接数多且连接比较长的架构,比如相册服务器。

    NIO编程

    2.1 NIO介绍

    Java NIO是JDK提供的新API。NIO有三个核心部分:Channel,Buffer,Selector。NIO是面向缓冲区编程的。JAVA NIO的非阻塞模式,是一个线程从某个通道发送或读取数据,仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是阻塞线程。

    通俗理解:NIO是可以做到用一个线程来处理多个操作的。假设有1000个请求过来,根据实际情况,可以分配50或100个线程来处理。不像BIO那样,非得分配1000个线程。

    NIO和BIO比较

    1. BIO是以流的方式处理数据,而NIO是以缓冲区的方式处理数据
    2. BIO是阻塞的,NIO是非阻塞的
    3. BIO基于字节流和字符流操作,而NIO是基于Channel和Buffer进行操作。NIO基于Selector监听多个通道的事件。
  • 相关阅读:
    我眼中的《视觉测量技术基础》
    What’s new in Grafana v11.0-preview
    MongoDB学习笔记
    linux之eventfd理解
    [Unity] GPU动画实现(三)——材质合并
    智慧教育解决方案-最新全套文件
    <二>强弱指针使用场景之 多线程访问共享对象问题
    blob和file对象文件API
    堆排序(Heap Sort)
    【C#】认识C# (为了游戏开发 O(≧口≦)O)
  • 原文地址:https://www.cnblogs.com/javammc/p/15890117.html