jdk的selector(2)channel的注册
2018-01-14 15:22
351 查看
Selector中的channel注册需要由SelectabelChannel调用其register()方法开始注册流程。具体的register()方法实现在了AbstractSelectableChannel中。
在channel中,将会有一个数组来保存已经注册过了的SelectionKey。一个SelectionKey代表一个channel和一个selector的注册关系。在注册的首先,会通过findKey()来寻找key判断这个channel是否已经注册过。如果这个channel是第一次进行注册操作,那么显然这里是找不到的。具体的findKey()方法实现如下。
如果一开始就找到了相应的key,说明该channel与传递进来需要注册的selctor已经注册过,那么就是对相应的interestOps和attach进行更新,并没有新的注册操作。
但是,如果没有找到相应的SelectionKey,就说明需要与传递进来的Selector进行注册操作。
Selector的register()方法实现在了SelectorImpl中。
首先,就会根据channel与selector生成相应的SelectionKeyImpl,其构造方法就是简单的保存了传递进来的参数,并且将所需要attach的object进行保存。之后,调用子类的implRegister()方法,以windowsSelectorImpl为例子。
在这里,便是对SelectionKeyImpl进行进一步的加工,已完成其对注册关系抽象的功能。
此处,由于需要存放新注册的SelectionKey,所以需要对原本存放相应对象的数组长度进行必要的检验,在growIfNeeded()方法中,如果此时数组的长度已经不够,则需要对该数组进行扩容。
之后,根据当前的channel数量将相应点的channel存放在数组相应的下标下的位置,并在SelectionKey中保存在被注册的selector中的位置索引。之后将在put()方法中完成所注册的channel的FDVal与具体的SelectionKey的键值对的映射。
最后,将该SelectionKey与当时的channel数量作为键值对保存在pollWrapper中,最后自增channel数。
当SelectionKey经过Selector的产生后边,将会返回给channel,这个时候通过addKey()将刚刚产生的key添加到channel中。
在addKey()方法中,如果此时大小还足够,那么可以直接在相应的位置顺序将SelectionKey保存,如果需要扩容,则会在扩容之后保存相应的SelectionKey。
public final SelectionKey register(Selector sel, int ops, Object att) throws ClosedChannelException { synchronized (regLock) { if (!isOpen()) throw new ClosedChannelException(); if ((ops & ~validOps()) != 0) throw new IllegalArgumentException(); if (blocking) throw new IllegalBlockingModeException(); SelectionKey k = findKey(sel); if (k != null) { k.interestOps(ops); k.attach(att); } if (k == null) { // New registration synchronized (keyLock) { if (!isOpen()) throw new ClosedChannelException(); k = ((AbstractSelector)sel).register(this, ops, att); addKey(k); } } return k; } }
在channel中,将会有一个数组来保存已经注册过了的SelectionKey。一个SelectionKey代表一个channel和一个selector的注册关系。在注册的首先,会通过findKey()来寻找key判断这个channel是否已经注册过。如果这个channel是第一次进行注册操作,那么显然这里是找不到的。具体的findKey()方法实现如下。
private SelectionKey findKey(Selector sel) { synchronized (keyLock) { if (keys == null) return null; for (int i = 0; i < keys.length; i++) if ((keys[i] != null) && (keys[i].selector() == sel)) return keys[i]; return null; } }
如果一开始就找到了相应的key,说明该channel与传递进来需要注册的selctor已经注册过,那么就是对相应的interestOps和attach进行更新,并没有新的注册操作。
但是,如果没有找到相应的SelectionKey,就说明需要与传递进来的Selector进行注册操作。
Selector的register()方法实现在了SelectorImpl中。
protected final SelectionKey register(AbstractSelectableChannel var1, int var2, Object var3) { if(!(var1 instanceof SelChImpl)) { throw new IllegalSelectorException(); } else { SelectionKeyImpl var4 = new SelectionKeyImpl((SelChImpl)var1, this); var4.attach(var3); Set var5 = this.publicKeys; synchronized(this.publicKeys) { this.implRegister(var4); } var4.interestOps(var2); return var4; } }
首先,就会根据channel与selector生成相应的SelectionKeyImpl,其构造方法就是简单的保存了传递进来的参数,并且将所需要attach的object进行保存。之后,调用子类的implRegister()方法,以windowsSelectorImpl为例子。
protected void implRegister(SelectionKeyImpl var1) { Object var2 = this.closeLock; synchronized(this.closeLock) { if(this.pollWrapper == null) { throw new ClosedSelectorException(); } else { this.growIfNeeded(); this.channelArray[this.totalChannels] = var1; var1.setIndex(this.totalChannels); this.fdMap.put(var1); this.keys.add(var1); this.pollWrapper.addEntry(this.totalChannels, var1); ++this.totalChannels; } } }
在这里,便是对SelectionKeyImpl进行进一步的加工,已完成其对注册关系抽象的功能。
此处,由于需要存放新注册的SelectionKey,所以需要对原本存放相应对象的数组长度进行必要的检验,在growIfNeeded()方法中,如果此时数组的长度已经不够,则需要对该数组进行扩容。
private void growIfNeeded() { if(this.channelArray.length == this.totalChannels) { int var1 = this.totalChannels * 2; SelectionKeyImpl[] var2 = new SelectionKeyImpl[var1]; System.arraycopy(this.channelArray, 1, var2, 1, this.totalChannels - 1); this.channelArray = var2; this.pollWrapper.grow(var1); } if(this.totalChannels % 1024 == 0) { this.pollWrapper.addWakeupSocket(this.wakeupSourceFd, this.totalChannels); ++this.totalChannels; ++this.threadsCount; } }
之后,根据当前的channel数量将相应点的channel存放在数组相应的下标下的位置,并在SelectionKey中保存在被注册的selector中的位置索引。之后将在put()方法中完成所注册的channel的FDVal与具体的SelectionKey的键值对的映射。
private WindowsSelectorImpl.MapEntry put(SelectionKeyImpl var1) { return (WindowsSelectorImpl.MapEntry)this.put(new Integer(var1.channel.getFDVal()), new WindowsSelectorImpl.MapEntry(var1)); }
最后,将该SelectionKey与当时的channel数量作为键值对保存在pollWrapper中,最后自增channel数。
当SelectionKey经过Selector的产生后边,将会返回给channel,这个时候通过addKey()将刚刚产生的key添加到channel中。
private void addKey(SelectionKey k) { assert Thread.holdsLock(keyLock); int i = 0; if ((keys != null) && (keyCount < keys.length)) { // Find empty element of key array for (i = 0; i < keys.length; i++) if (keys[i] == null) break; } else if (keys == null) { keys = new SelectionKey[3]; } else { // Grow key array int n = keys.length * 2; SelectionKey[] ks = new SelectionKey ; for (i = 0; i < keys.length; i++) ks[i] = keys[i]; keys = ks; i = keyCount; } keys[i] = k; keyCount++; }
在addKey()方法中,如果此时大小还足够,那么可以直接在相应的位置顺序将SelectionKey保存,如果需要扩容,则会在扩容之后保存相应的SelectionKey。
相关文章推荐
- 网络编程之SocketChannel & ServerSocketChannel & Selector
- Dubbo-Admin管理平台和Zookeeper注册中心的搭建(只支持jdk7)
- Netty5源码分析(三) -- Channel如何注册OP_ACCEPT, OP_READ, OP_WRITE
- selector与channel
- SocketChannel / ServerSocketChannel / Selector
- Java NIO学习8(Selector 补充版SocketChannel)
- NIO的Buffer&Channel&Selector
- 【NIO详解】Channel、Selector与Pipe
- NIO理解通道 selector SeverSocketChannel serverSocket selectionKey
- ServerSocketChannel实现多Selector高并发server
- NIO中Channel、Buffer、Selector详解
- jdk的Selector(3)select的过程
- ServerSocketChannel实现多Selector高并发server
- Flume Channel Selector
- Java NIO学习8(Selector 补充版DatagramChannel)
- Netty&Jdk的Selector对比
- Centos7.3 安装JDK以及注册Tomcat服务
- netty NioServerSocketChannel注册流程一
- bat注册tomcat加载指定jdk
- toad32和64位永久注册码插件Matlab数据分析工具weblogic下载linuxjdk1.764位