• NIO


    1. 背景

    SelectableChannel对象的多路复用器。

    可以通过调用Selector.open()方法创建Selector对象。Selector.open()方法会利用系统默认的SelectorProvider创建Selector对象。也可以通过自定义SelectorProvider对象的openSelector方法创建Selector。Selector会一直处于打开状态,直到调用它的close方法。

    SelectionKey对象表示每一个注册到Selector的SelectorChannel。每个Selector维护3个集合:

    • key集合:表示注册到该Selector的Channel,通过Channel的register方法可以往key集合中添加元素,取消的key在selection操作之间从key集合中移除,key集合不能直接修改,通过keys方法返回。
    • selected-key集合:在selection操作中,从所有的key集合中识别出已经ready的key对应的Channel。通过执行set的remove可以移除key或者执行迭代器对象的remove。否则key将不能通过其他方式移除。不可以直接增加到selected-key集合中。
    • cancelled-key集合:key已经被取消,但是对应的Channel还没有撤销,这个集合不可以直接访问,这个cancelled-key总是key集合的子集。当key被取消,close对应的Channel或执行它的cancel方法,则添加key到cancelled-key集合中。取消key将导致下一次Selection操作时它的通道被撤销,同时将从所有的Selector的key集合中删除。

    备注:新创建的Selector对象,这3个集合都是空集合。

    Selection

    在每次执行Selection操作时,key可能从selected-key集合中增加或删除,也可能从key集合和cancelled-key集合中删除。通过select(),select(long),selectNow()方法执行Selection操作,包含3个步骤:

    (1)

    2. Selector源码分析

    2.1 API

    public abstract class Selector implements Closeable {
    
        protected Selector() { }
    
        // 创建Selector对象
        public static Selector open() throws IOException {
            return SelectorProvider.provider().openSelector();
        }
    
        // 检测Selector是否打开
        public abstract boolean isOpen();
    
        // 返回创建该Selector的Provider
        public abstract SelectorProvider provider();
    
        // 返回Key集合,key集合不能被直接修改,只有在被cancel和channel被撤销的时候key才被移除。并且不是线程安全的集合。
        public abstract Set<SelectionKey> keys();
    
        // 返回selected-key集合,key可以直接移除,但是不可以直接增加。并且不是线程安全的集合。
        public abstract Set<SelectionKey> selectedKeys();
    
         // 选择channel有IO事件的key。
         // 该方法是非阻塞的selection操作,如果自上次selection操作之后无channel具有IO事件,该方法会立刻返回零。
         // 执行该方法会立刻清除之前执行的wakeup影响。
        public abstract int selectNow() throws IOException;
    
        // 阻塞操作,只有在以下的状态变化时:
        //(1)至少有一个IO的channel(2)调用selector.wakeup方法(3)当前线程被interrupt(4)timeout时间到(毫秒)
        public abstract int select(long timeout)
            throws IOException;
    
         // 阻塞操作,返回条件与select(long timeout)类似
        public abstract int select() throws IOException;
    
         // 唤醒当前select阻塞的操作:如果另一个线程当前阻塞在select或select(long)方法。
         // 如果当前没有select阻塞,则下次执行select或select(long)则直接返回,除非selectNow同时执行;
         //之后select和select(long)方法会正常阻塞;
         // 如果在select操作之间多次调用wakeup与调用一次效果是一样的
        public abstract Selector wakeup();
    
        // 关闭Selector。
        // 调用close方法,如果当前阻塞在selection操作,就像调用wakeup方法一样会立刻中断操作
        // 与该selector关联的未cancelled的key将失效,它们的channel将撤销,与Selector相关的其他资源将释放。
        // 如果Selector已经关闭,执行这个方法将没有影响。
        // selector关闭之后,如果执行与selector相关的操作会报ClosedSelectorException
        public abstract void close() throws IOException;
    
    }
    

    2.2 类图

     

    2.3 AbstractSelector

    AbstractSelector主要实现了Selector的打开关闭的状态维护,支持异步关闭和中断的begin和end方法,cancelledKeys等。

    package java.nio.channels.spi;
    
    import java.io.IOException;
    import java.nio.channels.SelectionKey;
    import java.nio.channels.Selector;
    import java.util.HashSet;
    import java.util.Set;
    import sun.nio.ch.Interruptible;
    import java.util.concurrent.atomic.AtomicBoolean;
    
    // Selector的基本实现。
    public abstract class AbstractSelector
        extends Selector
    {
    
        private AtomicBoolean selectorOpen = new AtomicBoolean(true); // 是否打开
    
        // The provider that created this selector
        private final SelectorProvider provider;
    
        protected AbstractSelector(SelectorProvider provider) {
            this.provider = provider;
        }
        // 三大key集合之一cancelledKeys
        private final Set<SelectionKey> cancelledKeys = new HashSet<SelectionKey>();
    
        void cancel(SelectionKey k) {                       // package-private
            synchronized (cancelledKeys) {
                cancelledKeys.add(k);
            }
        }
    
        public final void close() throws IOException {
            boolean open = selectorOpen.getAndSet(false);
            if (!open)
                return;
            implCloseSelector();// 只有在Selector未关闭的情况下调用,并且只能被调用一次。
        }
        // 关闭Selector
        // 这个方法被close方法调用去执行Selector的关闭操作,只有在Selector未关闭的情况下调用,并且只能被调用一次。具体参考上面close实现
        protected abstract void implCloseSelector() throws IOException;
    
        public final boolean isOpen() {
            return selectorOpen.get();
        }
    
        public final SelectorProvider provider() {
            return provider;
        }
    
        protected final Set<SelectionKey> cancelledKeys() {
            return cancelledKeys;
        }
    
        // 为Selector注册Channel,这个方法被AbstractSelectableChannel.register方法调用
        protected abstract SelectionKey register(AbstractSelectableChannel ch,
                                                 int ops, Object att);
    
        protected final void deregister(AbstractSelectionKey key) {
            ((AbstractSelectableChannel)key.channel()).removeKey(key);
        }
    
    
        // -- Interruption machinery --
    
        private Interruptible interruptor = null;
        // 支持异步关闭和中断的begin和end方法
        protected final void begin() {
            if (interruptor == null) {
                interruptor = new Interruptible() {
                        public void interrupt(Thread ignore) {
                            AbstractSelector.this.wakeup();
                        }};
            }
            AbstractInterruptibleChannel.blockedOn(interruptor);
            Thread me = Thread.currentThread();
            if (me.isInterrupted())
                interruptor.interrupt(me);
        }
    
        protected final void end() {
            AbstractInterruptibleChannel.blockedOn(null);
        }
    
    }  

    备注:支持异步关闭和中断的机制,可以参考http://www.cnblogs.com/lujiango/p/8478154.html

    2.4 SelectorImpl

    package sun.nio.ch;
    
    import java.io.IOException;
    import java.nio.channels.*;
    import java.nio.channels.spi.*;
    import java.net.SocketException;
    import java.util.*;
    import sun.misc.*;
    
    
    // Selector的基本实现
    abstract class SelectorImpl
        extends AbstractSelector
    {
    
        // 已经准备IO的keys
        protected Set<SelectionKey> selectedKeys;
    
        // 注册到该Selector的所有key
        protected HashSet<SelectionKey> keys;
    
        // Public views of the key sets
        private Set<SelectionKey> publicKeys;             // 不可变
        private Set<SelectionKey> publicSelectedKeys;     // 可删除,不可增加
    
        protected SelectorImpl(SelectorProvider sp) {
            super(sp);
            keys = new HashSet<SelectionKey>();
            selectedKeys = new HashSet<SelectionKey>();
            if (Util.atBugLevel("1.4")) {
                publicKeys = keys;
                publicSelectedKeys = selectedKeys;
            } else {
                publicKeys = Collections.unmodifiableSet(keys);
                publicSelectedKeys = Util.ungrowableSet(selectedKeys);
            }
        }
    
        public Set<SelectionKey> keys() {
            if (!isOpen() && !Util.atBugLevel("1.4"))
                throw new ClosedSelectorException();
            return publicKeys;
        }
    
        public Set<SelectionKey> selectedKeys() {
            if (!isOpen() && !Util.atBugLevel("1.4"))
                throw new ClosedSelectorException();
            return publicSelectedKeys;
        }
        // 对于Windows系统,需要WindowsSelectorImpl实现doSelect方法
        protected abstract int doSelect(long timeout) throws IOException; 
    
        private int lockAndDoSelect(long timeout) throws IOException {
            synchronized (this) {
                if (!isOpen())
                    throw new ClosedSelectorException();
                synchronized (publicKeys) {
                    synchronized (publicSelectedKeys) {
                        return doSelect(timeout);
                    }
                }
            }
        }
        // select方法的实现
        public int select(long timeout)
            throws IOException
        {
            if (timeout < 0)
                throw new IllegalArgumentException("Negative timeout");
            return lockAndDoSelect((timeout == 0) ? -1 : timeout);
        }
    
        public int select() throws IOException {
            return select(0);
        }
    
        public int selectNow() throws IOException {
            return lockAndDoSelect(0);
        }
    
        public void implCloseSelector() throws IOException {
            wakeup();
            synchronized (this) {
                synchronized (publicKeys) {
                    synchronized (publicSelectedKeys) {
                        implClose();
                    }
                }
            }
        }
        // 需要WindowsSelectorImpl实现
        protected abstract void implClose() throws IOException;
    
        void putEventOps(SelectionKeyImpl sk, int ops) { }
    
        protected final SelectionKey register(AbstractSelectableChannel ch,
                                              int ops,
                                              Object attachment)
        {
            if (!(ch instanceof SelChImpl))
                throw new IllegalSelectorException();
            SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
            k.attach(attachment);
            synchronized (publicKeys) {
                implRegister(k);
            }
            k.interestOps(ops);
            return k;
        }
    
        protected abstract void implRegister(SelectionKeyImpl ski);
    
        void processDeregisterQueue() throws IOException {
            // Precondition: Synchronized on this, keys, and selectedKeys
            Set cks = cancelledKeys();
            synchronized (cks) {
                if (!cks.isEmpty()) {
                    Iterator i = cks.iterator();
                    while (i.hasNext()) {
                        SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
                        try {
                            implDereg(ski);
                        } catch (SocketException se) {
                            IOException ioe = new IOException(
                                "Error deregistering key");
                            ioe.initCause(se);
                            throw ioe;
                        } finally {
                            i.remove();
                        }
                    }
                }
            }
        }
    
        protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
    
        abstract public Selector wakeup(); // 定义唤醒方法
    
    }
    

      

    2.5 WindowsSelectorImpl和EPollSelectorImpl

    具体会分析windows平台的WindowsSelectorImpl,Linux平台的EPollSelectorImpl暂时不做分析。

    3. WindowsSelectorImpl

      

  • 相关阅读:
    redis未授权访问简单总结
    CORS跨域资源共享漏洞初探
    Mysql UDF提权方法
    hacknos-player靶机渗透
    深入理解Java虚拟机-类加载连接和初始化解析
    Dnslog盲注
    让服务器使用密钥
    自动备份站点
    自动放行nginx后台访问ip
    mysql增备
  • 原文地址:https://www.cnblogs.com/lujiango/p/8458214.html
Copyright © 2020-2023  润新知