2023-01-14  阅读(47)
原文作者: HelloWorld_EE 原文地址:https://blog.csdn.net/u010412719/category_6159934_2.html

《Java 源码分析》:Java NIO 之 SelectionKey

在ServerSocketChannel源码分析中我们知道当把一个channel注册到指定的Selector上时,
实际上就是将(channel,selector)封装成了一个SelectionKey对象,并将此对象保存在了Selector对象中。

SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);

在Java NIO 的一些小Demo中,我们常常会看见这样的代码:

                    // 当注册事件到达时,方法返回,否则该方法会一直阻塞 
                    selector.select();
                    // 获得selector中选中的相的迭代器,选中的相为注册的事件 
                    Set<SelectionKey> set = selector.selectedKeys();
                    Iterator<SelectionKey> ite = set.iterator();
                    while(ite.hasNext()){
                        SelectionKey selectionKey = (SelectionKey) ite.next();
                        // 删除已选的key 以防重负处理  
                        ite.remove(); 
                        if(selectionKey.isAcceptable()){//如果有客户端连接进来
                            //先拿到这个SelectionKey里面的ServerSocketChannel。
                            ServerSocketChannel serverSocketChannel = (ServerSocketChannel)selectionKey.channel();
                            // do something....
                        }
                    }

今天我们就来看下这个类.

SelectionKeyImpl类中的几个重要属性如下:

        final SelChImpl channel;  所拥有的channel对象,该属性是包私有的
        final SelectorImpl selector;   所拥有的selector对象,该属性是包私有的                   
    
        // Index for a pollfd array in Selector that this key is registered with
        private int index; //其值表示该SelectionKey对象存储在与其关联的Selector对象中所在的位置
    
        private volatile int interestOps; //集合
        private int readyOps;

构造方法

        SelectionKeyImpl(SelChImpl ch, SelectorImpl sel) {
            channel = ch;
            selector = sel;
        }

以下是这个类中用来获取该对象中所关联的 channel、selector的方法

        public SelectableChannel channel() {
            return (SelectableChannel)channel;
        }
    
        public Selector selector() {
            return selector;
        }
    
        int getIndex() {                                    // package-private
            return index;
        }
    
        void setIndex(int i) {                              // package-private
            index = i;
        }

都比较简单,容易理解哈。

在编程中我们使用channel.register(selector,interestSet)方法来将channel注册到指定的selector中。这个方法的第二个参数。这是一个“interest集合”,意思是在通过Selector监听此Channel时对什么事件感兴趣。可以监听四种不同类型的事件:

1、Connect

2、Accept

3、Read

4、Write

通道channel触发了一个事件的意思是该事件已经就绪。所以,如果某个channel成功连接到另一个服务器称为“连接就绪”。如果一个ServerSocketChannel准备好接收新进入的连接称为“接收就绪”。如果一个有数据可读的通道可以说是“读就绪”。等待写数据的通道可以说是“写就绪”。

这四种事件用SelectionKey的四个常量来表示,如下:

1、SelectionKey.OP_CONNECT

2、SelectionKey.OP_ACCEPT

3、SelectionKey.OP_READ

4、SelectionKey.OP_WRITE

如果你对不止一种事件感兴趣,那么可以用“位或”操作符将常量连接起来,如下:

int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

在SelectionKey类的源码中我们可以看到如下的4中属性,四个变量用来表示四种不同类型的事件:可读、可写、可连接、可接受连接

       public static final int OP_READ = 1 << 0;
    
    
        public static final int OP_WRITE = 1 << 2;
    
    
        public static final int OP_CONNECT = 1 << 3;
    
    
        public static final int OP_ACCEPT = 1 << 4;

SelectionKey类还提供了以下几个方法用来检测channel中什么事件或操作已经就绪

        //测试此通道是否可读
        public final boolean isReadable() {
            return (readyOps() & OP_READ) != 0;
        }
    
        //测试此通道是否可读
        public final boolean isWritable() {
            return (readyOps() & OP_WRITE) != 0;
        }
    
        //检查连接是否完成
        public final boolean isConnectable() {
            return (readyOps() & OP_CONNECT) != 0;
        }
    
    
        //测试这个SelectionKey对应的通道是否已经接受了一个新的Socket连接。
        public final boolean isAcceptable() {
            return (readyOps() & OP_ACCEPT) != 0;
        }

小结

以上,我们就简单的看了下SelectionKey类,SelectionKey类简单来说就是一个辅助类,比较简单。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文