NIO源码分析:SelectionKey,GitHub已标星16k

================

SelectionKey,选择键,在每次通道注册到选择器上时都会创建一个SelectionKey储存在该选择器上,该SelectionKey保存了注册的通道、注册的选择器、通道事件类型操作符等信息。

SelectionKey是一个抽象类,它有俩个实现类了AbstractSelectionKey(抽象类)SelectionKeyImpl(最终实现类)。SelectionKey有6个属性:

//读操作符,左移位后的整型值为1

public static final int OP_READ = 1 << 0;

//写操作符,左移位后的整型值为4

public static final int OP_WRITE = 1 << 2;

//连接操作符,左移位后的整型值为8

public static final int OP_CONNECT = 1 << 3;

//接收操作符,左移位后的整型值为16

public static final int OP_ACCEPT = 1 << 4;

//附件

private volatile Object attachment = null;

//附件更新者,当要更新附件时需调用该对象的方法

private static final AtomicReferenceFieldUpdater<SelectionKey,Object>

attachmentUpdater = AtomicReferenceFieldUpdater.newUpdater(

SelectionKey.class, Object.class, “attachment”

);

这些属性中较为重要的是4个操作符属性,需记住它们左移位后的整型值,在后面对选择通道的操作事件判断需使用到。

SelectionKey除开构造器方法,有13个方法:

public abstract SelectableChannel channel();//返回该SelectionKey对应通道

public abstract Selector selector();//返回该SelectionKey注册的选择器

public abstract boolean isValid();//判断该SelectionKey是否有效

public abstract void cancel();//撤销该SelectionKey

public abstract int interestOps();//返回SelectionKey的关注操作符

//设置该SelectionKey的关注键,返回更改后新的SelectionKey

public abstract SelectionKey interestOps(int ops);

public abstract int readyOps();//返回SelectionKey的预备操作符

//这里readyOps()方法返回的是该SelectionKey的预备操作符,至于什么是预备操作符在最终实现类SelectionKeyImpl中会讲解。

//判断该SelectionKey的预备操作符是否是OP_READ

public final boolean isReadable() {

return (readyOps() & OP_READ) != 0;

}

//判断该SelectionKey的预备操作符是否是OP_WRITE

public final boolean isWritable() {

return (readyOps() & OP_WRITE) != 0;

}

//判断该SelectionKey的预备操作符是否是OP_CONNECT

public final boolean isConnectable() {

return (readyOps() & OP_CONNECT) != 0;

}

//判断该SelectionKey的预备操作符是否是OP_ACCEPT

public final boolean isAcceptable() {

return (readyOps() & OP_ACCEPT) != 0;

}

//设置SelectionKey的附件

public final Object attach(Object ob) {

return attachmentUpdater.getAndSet(this, ob);

}

//返回SelectionKey的附件

public final Object attachment() {

return attachment;

}

AbstractSelectionKey

=====================

AbstractSelectionKey继承了SelectionKey类,它也是一个抽象类,相比其他俩个类,它的代码就简洁多了,它只有一个属性:

//用于判断该SelectionKey是否有效,true为有效,false为无效,默认有效

private volatile boolean valid = true;

AbstractSelectionKey除开构造器方法,只要三个实现方法:

//判断该SelectionKey是否有效

public final boolean isValid() {

return valid;

}

//将该SelectionKey设为无效

void invalidate() {

valid = false;

}

//将该SelectionKey从选择器中删除

//注意,删除的SelectionKey并不会马上从选择器上删除,而是会加入一个需删除键的集合中,等到下一次调用选择方法才会将它从选择器中删除,至于具体实现会在选择器源码分析章节中讲

public final void cancel() {

synchronized (this) {

if (valid) {

valid = false;

((AbstractSelector)selector()).cancel(this);

}

}

}

SelectionKeyImpl

====================

SelectionKeyImpl是SelectionKey的最终实现类,它继承了AbstractSelectionKey类,在该类中不仅实现了SelectionKey和抽象类的方法,而且扩展了其他方法。

SelectionKeyImpl的属性

=======================

SelectionKeyImpl中有5个新的属性:

//该SelectionKey对应的通道

final SelChImpl channel;

//该SelectionKey注册的选择器

public final SelectorImpl selector;

//该SelectionKey在注册选择器中储存SelectionKey集合中的下标索引,当该SelectionKey被撤销时,index为-1

private int index;

//SelectionKey的关注操作符

private volatile int interestOps;

//SelectionKey的预备操作符

private int readyOps;

从上面属性中可以看到,SelectionKeyImpl有俩个操作符属性:关注操作符interestOps预备操作符readyOps

interestOps是储存通道的注册方法register(Selector sel, int ops)输入的ops参数,可以在register方法的最终实现中看出,代表程序需选择器对通道关注的操作事件。

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) {

//将输入的参数ops储存在SelectionKey的interestOps属性中

k.interestOps(ops);

k.attach(att);

}

if (k == null) {

synchronized (keyLock) {

if (!isOpen())

throw new ClosedChannelException();

k = ((AbstractSelector)sel).register(this, ops, att);

addKey(k);

}

}

return k;

}

}

readyOps是通道实际发生的操作事件,当我们对选择器Selector.select()方法层层追溯,到达该方法的最终实现doSelect(long var1)方法,会发现doSelect方法调用了一个updateSelectedKeys()方法来更新选择器的SelectionKey集合,而updateSelectedKeys方法又调用了updateSelectedKeys(this.updateCount)方法来进行实际的更新操作,而updateSelectedKeys方法最终通过processFDSet方法来实现更新。在processFDSet方法里有两个方法调用实现了SelectionKey里readyOps属性的更新:translateAndSetReadyOps(用于设置readyOps)translateAndUpdateReadyOps(用于更新readyOps)

public boolean translateAndUpdateReadyOps(int var1, SelectionKeyImpl var2) {

return this.translateReadyOps(var1, var2.nioReadyOps(), var2);

}

public boolean translateAndSetReadyOps(int var1, SelectionKeyImpl var2) {

return this.translateReadyOps(var1, 0, var2);

}

通过观察两个方法,可以发现它们都调用了translateReadyOps方法:

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后如何让自己一步步成为技术专家

说句实话,如果一个打工人不想提升自己,那便没有工作的意义,毕竟大家也没有到养老的年龄。

当你的技术在一步步贴近阿里p7水平的时候,毫无疑问你的薪资肯定会涨,同时你能学到更多更深的技术,交结到更厉害的大牛。

推荐一份Java架构之路必备的学习笔记,内容相当全面!!!

成年人的世界没有容易二字,前段时间刷抖音看到一个程序员连着加班两星期到半夜2点的视频。在这个行业若想要拿高薪除了提高硬实力别无他法。

你知道吗?现在有的应届生实习薪资都已经赶超开发5年的程序员了,实习薪资26K,30K,你没有紧迫感吗?做了这么多年还不如一个应届生,真的非常尴尬!

进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!

【关注】+【转发】+【点赞】支持我!创作不易!

平的时候,毫无疑问你的薪资肯定会涨,同时你能学到更多更深的技术,交结到更厉害的大牛。

推荐一份Java架构之路必备的学习笔记,内容相当全面!!!

[外链图片转存中…(img-r06m04Ip-1711150986081)]

成年人的世界没有容易二字,前段时间刷抖音看到一个程序员连着加班两星期到半夜2点的视频。在这个行业若想要拿高薪除了提高硬实力别无他法。

你知道吗?现在有的应届生实习薪资都已经赶超开发5年的程序员了,实习薪资26K,30K,你没有紧迫感吗?做了这么多年还不如一个应届生,真的非常尴尬!

进了这个行业就不要把没时间学习当借口,这个行业就是要不断学习,不然就只能被裁员。所以,抓紧时间投资自己,多学点技术,眼前困难,往后轻松!

【关注】+【转发】+【点赞】支持我!创作不易!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值