• JavaNIO


    javaNIO对于多路复用io(同步非阻塞io)的实现

    package test;
    
    import java.io.IOException;
    import java.net.InetSocketAddress;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.nio.channels.ServerSocketChannel;
    import java.nio.channels.SocketChannel;
    import java.util.Iterator;
    
    public class NioPractice {
    
        public static void main(String[] args) throws IOException {
            // TODO Auto-generated method stub
    
            //开启一个ServerSocketChannel在端口8080监听
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.bind(new InetSocketAddress("localhost", 8080));
            //开启一个多路复用器,可以实现用一个线程监控所有IO连接的IO就绪事件
            
            Selector selector=Selector.open();
            //将severSocketChannel注册到多路复用器上,并声明关注其accept就绪事件
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            
            while(selector.select()!=0) {
                Iterator<SelectionKey> iterator=selector.selectedKeys().iterator();
                while(iterator.hasNext()) {
                    SelectionKey key=iterator.next();
                    if(key.isReadable()) {
                        //将Channel里的数据读出,当有大量数据需要读取时,导致监控线程一直为这个io服务,
                        //因此可以专门开一个线程池来对io读写处理(不由监控线程来处理,由新开的线程池来处理,所以监控线程可以去处理别的就绪事件)
                    }
                    if(key.isWritable()) {
                        
                    }
                    if(key.isAcceptable()) {
                        //统一由selector多路复用器来监听,当socketChannel为非阻塞时,省去了单独判断它是否成功接受连接
                        SocketChannel socketChannel=serverSocketChannel.accept();
                        //将socketChannel注册到多路复用器上,并声明关注其read事件
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        
                        
                        
                    }
                    iterator.remove();
                    
                }
            }
            
            
        }
    
    }

    基于 Java NIO 的事件分离模式

    采用 Java NIO 技术实现的典型的两种高效、应用广泛的事件分离模式:一个是反应器(Reactor)模式,一个是前摄器(Proactor)模式。

     同步非阻塞io

    反应器(Reactor)模式目的是使服务器具有并发处理服务请求的能力。服务器首先注册多个事件处理器(Event Handler),事件分离器(Event Demultiplexer)负责接收一个或者多个客户端发来的请求,并将事件分发到对应的事件处理器上。

    一个典型的读操作的过程是:

    1)  服务器程序注册 Accept 事件,事件分离器等待客户端的连接请求;

    2)  客户端请求到来后,将连接事件分发到 Acceptor 事件处理器中,建立连接。

    3)  连接建立完成后服务器程序再注册一个读操作事件。事件分离器继续等待事件发生;

    4)  当读操作在对应的连接上就绪后,事 件分离器分发事件到对应的Read Handler 事件处理器中基于同步 I/O 进行阻塞读取;

    5)  读取完成后再根据业务需要做进一步处理。 整个过程是由服务器感兴趣的事件触发的,因此形象的叫做反应器模式。


     异步非阻塞io

    前摄器(Proactor)模式也是一种事件分离模式,与 Reactor 不同的是基于异步 I/O 的,实现了真正的无阻塞异步的 I/O 操作。前摄器模式同样是分离事件给对应的事件处理器,然而这里的事件不再是就绪事件,如就绪读或者就绪写,而是异步操作的完成事件。

    一个典型的读操作处理过程如下:

    1)  服务器程序注册 Accept 事件,事件分离器等待客户端的连接请求;

    2)  客户端请求到来后,将连接事件分发到 Acceptor 事件处理器中,建立连接。

    3)  连接建立完成后服务器程序再注册一个读操作完成事件。事件分离器继续读操作完成事件的发生;

    4)  当读操作在对应的连接上就绪后,由操作系统触发一个异步读取操作,等读取完成后,会将读取内容放在用户指定的缓冲区,并通知应用程序事件完成。

    5)  事件分离器接收到完成事件后,将事件分发到 ReadHandler 事件处理器中直接从指定缓冲区中取出数据,而不需要进行实际的 I/O 操作。

    6)  缓冲区数据取出后再根据不同的业务做进一步的处理

    典型的异步模式实现,都建立在操作系统支持异步 API 的基础之上,这种实现称为系统级异步,因为应用程序完全依赖操作系统执行真正的 I/O 工作 

    这两个模式都使用了事件驱动模型:一个是在数据准备好时通知事件处理器去进行io处理,一个 是在已经完成了io处理后通知事件处理器进行业务处理

    事件驱动模型图

    使用JavaAIO对文件进行异步读写的实现如下:

    package test;
    
    import java.io.IOException;
    import java.nio.ByteBuffer;
    import java.nio.channels.AsynchronousFileChannel;
    import java.nio.channels.CompletionHandler;
    import java.nio.file.Files;
    import java.nio.file.Path;
    import java.nio.file.Paths;
    import java.nio.file.StandardOpenOption;
    
    public class AIOtest1 {
    
        public static void main(String[] args) throws IOException {
            // TODO Auto-generated method stub
            Path path = Paths.get("test-write.txt");
            if(!Files.exists(path)){
                Files.createFile(path);
            }
            AsynchronousFileChannel fileChannel = 
                AsynchronousFileChannel.open(path, StandardOpenOption.WRITE);
    
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            long position = 0;
    
            buffer.put("test data".getBytes());
            buffer.flip();
            
            fileChannel.write(buffer, position, buffer, new CompletionHandler<Integer, ByteBuffer>() {
    
                @Override
                public void completed(Integer result, ByteBuffer attachment) {
                    System.out.println("bytes written: " + result);
                }
    
                @Override
                public void failed(Throwable exc, ByteBuffer attachment) {
                    System.out.println("Write failed");
                    exc.printStackTrace();
                }
            });
    
        }
    
    }

    参考:

    论文:基于Netty的高可服务消息中间件的研究与实现_崔晓旻

    博客:Java进阶知识点5:服务端高并发的基石 - NIO与Reactor模式以及AIO与Proactor模式

    Java NIO AsynchronousFileChannel

  • 相关阅读:
    JS—图片压缩上传(单张)
    vue 使用jssdk分享
    微信JS-SDK选择图片遇到的坑
    手把手教你实现一个微信自动回复机器人
    SSH实现远程控制
    使用Apache服务部署静态网站
    Rhel7安装及网卡、yum、vmtools配置和修改主机名
    基础工具之消息队列、线程池、缓冲区抽象、事件循环和日志实现
    I/O多路复用方案
    Java按字节截取字符串(GBK编码、UTF-8编码实现)
  • 原文地址:https://www.cnblogs.com/cai-cai777/p/10259985.html
Copyright © 2020-2023  润新知