一切旧绪 2021-01-05 11:12 采纳率: 0%
浏览 23

NIO多路复用模式中,用户线程在读写前可以不用阻塞等待数据到来,那么它去干什么了?

NIO多路复用模式中,用户线程在读写前可以不用阻塞等待数据到来,交给selector去监控,那么它去干什么了?

1、用户线程如果不阻塞,继续往下走,那我的应用程序岂不是没有数据返回,那不就是返回null了?

2、很多帖子说nio释放了资源,用户线程可以做其它事情,那这样岂不是线程不安全的?

 

  • 写回答

2条回答 默认 最新

  • damoneric_guo 2021-01-05 13:46
    关注

    在多路复用IO模型中,会有一个线程(Java中的Selector)不断去轮询多个socket的状态,只有当socket真正有读写事件时,才真正调用实际的IO读写操作。因为在多路复用IO模型中,只需要使用一个线程就可以管理多个socket,系统不需要建立新的进程或者线程,也不必维护这些线程和进程,并且只有在真正有socket读写事件进行时,才会使用IO资源,所以它大大减少了资源占用。

    什么是线程安全,这个要弄清楚,当多个线程访问某个方法时,不管你通过怎样的调用方式或者说这些线程如何交替的执行,我们在主程序中不需要去做任何的同步,这个类的结果行为都是我们设想的正确行为,那么我们就可以说这个类是线程安全的。

    单线程模式肯定是线程安全的

    那我们看看多线程的实现代码

    public class Reactor implements Runnable {
        public final Selector selector;
        public final ServerSocketChannel serverSocketChannel;
    
    
        public Reactor(int port) throws IOException {
            //用于监控fds
            selector=Selector.open();
            //socket服务器的chanel
            serverSocketChannel=ServerSocketChannel.open();
    
            InetSocketAddress inetSocketAddress=new InetSocketAddress(InetAddress.getLocalHost(),port);
            //
            serverSocketChannel.socket().bind(inetSocketAddress);
            //不设置阻塞队列
            serverSocketChannel.configureBlocking(false);
    
            //向selector注册该channel 返回selectionKey
            SelectionKey selectionKey=serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    
            //利用selectionKey的attache功能绑定Acceptor 如果有事情,触发Acceptor
            selectionKey.attach(new Acceptor(this));
        }
    
    
        public void run() {
            try {
                while(!Thread.interrupted()){
                    selector.select();//selector 阻塞
                    Set<SelectionKey> selectionKeys= selector.selectedKeys();
                    Iterator<SelectionKey> it=selectionKeys.iterator();
                    //Selector如果发现channel有OP_ACCEPT或READ事件发生,下列遍历就会进行。
                    while(it.hasNext()){
                        //来一个事件 第一次触发一个accepter线程
                        //以后触发SocketReadHandler
                        SelectionKey selectionKey=it.next();
                        dispatch(selectionKey);
                        selectionKeys.clear();
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        /**
         * 运行Acceptor或SocketReadHandler
         * @param key
         */
        void dispatch(SelectionKey key) {
            Runnable r = (Runnable)(key.attachment());
            if (r != null){
                r.run();
            }
        }
    }

    运行结果不会受到这些线程如何交替的执行,而结果发生改变。

    评论

报告相同问题?

悬赏问题

  • ¥60 求一个简单的网页(标签-安全|关键词-上传)
  • ¥35 lstm时间序列共享单车预测,loss值优化,参数优化算法
  • ¥15 基于卷积神经网络的声纹识别
  • ¥15 Python中的request,如何使用ssr节点,通过代理requests网页。本人在泰国,需要用大陆ip才能玩网页游戏,合法合规。
  • ¥100 为什么这个恒流源电路不能恒流?
  • ¥15 有偿求跨组件数据流路径图
  • ¥15 写一个方法checkPerson,入参实体类Person,出参布尔值
  • ¥15 我想咨询一下路面纹理三维点云数据处理的一些问题,上传的坐标文件里是怎么对无序点进行编号的,以及xy坐标在处理的时候是进行整体模型分片处理的吗
  • ¥15 CSAPPattacklab
  • ¥15 一直显示正在等待HID—ISP